├── boot ├── tests │ ├── status.rs │ └── image.rs ├── data │ ├── sample.bin │ ├── sample-signed.bin │ └── gen.sh ├── Cargo.toml ├── src │ ├── lib.rs │ ├── image.rs │ └── status.rs └── Cargo.lock ├── .gitignore ├── boards ├── lpc55s69 │ ├── build.rs │ ├── memory.x │ ├── .cargo │ │ └── config.toml │ ├── Makefile │ ├── jlink.gdb │ ├── Cargo.toml │ ├── src │ │ ├── flash.rs │ │ └── main.rs │ └── Cargo.lock └── stm32h745 │ ├── .cargo │ └── config.toml │ ├── Makefile │ ├── jlink.gdb │ ├── debug.gdb │ ├── build.rs │ ├── Cargo.toml │ ├── memory.x │ ├── src │ └── main.rs │ └── Cargo.lock ├── hello └── lpc55s69 │ ├── build.rs │ ├── .gitignore │ ├── .cargo │ └── config.toml │ ├── jlink.gdb │ ├── memory.x │ ├── Makefile │ ├── Cargo.toml │ ├── src │ └── main.rs │ └── Cargo.lock ├── .gitmodules ├── asraw ├── Cargo.lock ├── Cargo.toml └── src │ └── lib.rs ├── storage ├── Cargo.lock ├── Cargo.toml └── src │ └── lib.rs ├── simflash ├── Cargo.toml ├── src │ ├── gen.rs │ ├── styles.rs │ └── lib.rs └── Cargo.lock ├── LICENSE-MIT ├── README.md └── LICENSE-APACHE /boot/tests/status.rs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .gdb_history 3 | -------------------------------------------------------------------------------- /boards/lpc55s69/build.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /hello/lpc55s69/build.rs: -------------------------------------------------------------------------------- 1 | fn main() {} 2 | -------------------------------------------------------------------------------- /hello/lpc55s69/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore the generated binaries. 2 | *.bin -------------------------------------------------------------------------------- /boot/data/sample.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu-tools/mcuboot-rs/HEAD/boot/data/sample.bin -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lpc55-hal"] 2 | path = lpc55-hal 3 | url = https://githuyb.com/mcu-tools/lpc55-hal 4 | -------------------------------------------------------------------------------- /boot/data/sample-signed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mcu-tools/mcuboot-rs/HEAD/boot/data/sample-signed.bin -------------------------------------------------------------------------------- /boards/lpc55s69/memory.x: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 512K 4 | RAM : ORIGIN = 0x20000000, LENGTH = 256K 5 | } 6 | -------------------------------------------------------------------------------- /asraw/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "asraw" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /storage/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "storage" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /asraw/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "asraw" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | 10 | [features] 11 | default = ["std"] 12 | std = [] -------------------------------------------------------------------------------- /hello/lpc55s69/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] 2 | rustflags = [ 3 | "-C", "link-arg=-Tlink.x", 4 | ] 5 | # runner = "probe-rs run --chip LPC55S69JBD64" 6 | runner = "arm-none-eabi-gdb -q -x jlink.gdb" 7 | 8 | [build] 9 | target = "thumbv8m.main-none-eabi" -------------------------------------------------------------------------------- /storage/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "storage" 3 | version = "0.1.0" 4 | edition = "2021" 5 | documentation = "Embedded storage replacement" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | 11 | [features] 12 | default = ["std"] 13 | std = [] 14 | -------------------------------------------------------------------------------- /boards/stm32h745/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.thumbv7em-none-eabihf] 2 | runner = "arm-none-eabi-gdb -q -x jlink.gdb" 3 | rustflags = [ 4 | "-C", "link-arg=-Tdefmt.x", 5 | "-C", "link-arg=-Tlink.x", 6 | ] 7 | 8 | [build] 9 | target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) 10 | 11 | [env] 12 | DEFMT_LOG = "debug" 13 | -------------------------------------------------------------------------------- /boards/lpc55s69/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] 2 | rustflags = [ 3 | # "-C", "linker=flip-link", 4 | "-C", "link-arg=-Tlink.x", 5 | # "-C", "link-arg=-Tdefmt.x", 6 | ] 7 | # runner = "probe-rs run --chip LPC55S69JBD64" 8 | runner = "arm-none-eabi-gdb -q -x jlink.gdb" 9 | 10 | [build] 11 | target = "thumbv8m.main-none-eabi" 12 | -------------------------------------------------------------------------------- /boards/lpc55s69/Makefile: -------------------------------------------------------------------------------- 1 | # Make for silly stuff 2 | 3 | all: 4 | echo all is not a useful target. 5 | 6 | # Start the jlink server so gdb can program the board. 7 | jlink: 8 | env -u DISPLAY \ 9 | JLinkGDBServer -strict -device LPC55S69 -if SWD -vd 10 | 11 | semi: 12 | socat - TCP4:localhost:2333 13 | 14 | rtt: 15 | defmt-print -e target/thumbv8m.main-none-eabi/debug/mcuboot-lpc55s69 tcp 16 | -------------------------------------------------------------------------------- /boot/data/gen.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Generate a simple image. The data is random, so will be different each time this script is run. 4 | 5 | out=sample.bin 6 | 7 | dd if=/dev/zero bs=256 count=1 > $out 8 | dd if=/dev/urandom bs=1024 count=75 >> $out 9 | 10 | imgtool sign \ 11 | sample.bin sample-signed.bin \ 12 | --align 4 \ 13 | -v "0.1.0" \ 14 | --header-size 256 \ 15 | --slot-size 0x20000 16 | -------------------------------------------------------------------------------- /hello/lpc55s69/jlink.gdb: -------------------------------------------------------------------------------- 1 | # Debug using gdb 2 | 3 | set history save on 4 | set confirm off 5 | 6 | # find commit-hash using `rustc -Vv` 7 | set substitute-path /rustc/cc66ad468955717ab92600c770da8c1601a4ff33 \ 8 | /home/davidb/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust 9 | 10 | target extended-remote :2331 11 | load 12 | monitor reset 13 | 14 | monitor semihosting enable 15 | # monitor semihosting breakOnError 16 | # monitor semihosting IOClient 3 17 | 18 | # continue -------------------------------------------------------------------------------- /hello/lpc55s69/memory.x: -------------------------------------------------------------------------------- 1 | /* Partition table for development. 2 | 0 - 128k - bootloader 3 | 128k - 384k - slot 0 4 | 384k - 640k - slot 1 5 | */ 6 | MEMORY 7 | { 8 | BOOT_HEADER : ORIGIN = 0x0020000, LENGTH = 1024 9 | FLASH : ORIGIN = 0x00020000 + 1024, LENGTH = 256K - 1024 10 | RAM : ORIGIN = 0x20000000, LENGTH = 256K 11 | } 12 | 13 | SECTIONS { 14 | /* ### Boot header */ 15 | .boot_header ORIGIN(BOOT_HEADER) : 16 | { 17 | KEEP(*(.boot_header)); 18 | } > BOOT_HEADER 19 | } INSERT BEFORE .text; 20 | -------------------------------------------------------------------------------- /hello/lpc55s69/Makefile: -------------------------------------------------------------------------------- 1 | # Make for silly stuff 2 | 3 | all: 4 | echo all is not a useful target. 5 | 6 | # Start the jlink server so gdb can program the board. 7 | not-jlink: 8 | env -u DISPLAY \ 9 | JLinkGDBServer -strict -device LPC55S69 -if SWD -vd 10 | 11 | # Generate the signed image 12 | sign: signed.bin 13 | signed.bin: 14 | cargo objcopy -- -O binary unsigned.bin 15 | imgtool sign \ 16 | unsigned.bin signed.bin \ 17 | --align 4 \ 18 | -v '0.1.0' \ 19 | --header-size 1024 \ 20 | --slot-size 0x40000 21 | 22 | .PHONY: signed.bin 23 | -------------------------------------------------------------------------------- /simflash/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simflash" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies.storage] 9 | version = "0.1.0" 10 | path = "../storage" 11 | default-features = false 12 | 13 | [dependencies] 14 | anyhow = "1.0.75" 15 | rand = "0.8.5" 16 | rand_xoshiro = "0.6.0" 17 | temp-dir = "0.1.11" 18 | 19 | [dev-dependencies.boot] 20 | version = "0.1.0" 21 | path = "../boot" 22 | features = ["std"] 23 | 24 | [features] 25 | default = ["std"] 26 | std = ["storage/std"] 27 | -------------------------------------------------------------------------------- /boards/stm32h745/Makefile: -------------------------------------------------------------------------------- 1 | # Make for silly stuff 2 | 3 | all: 4 | echo all is not a useful target. 5 | 6 | # Start the jlink server so gdb can program the board. 7 | jlink: 8 | env -u DISPLAY \ 9 | JLinkGDBServer -strict -device STM32H745ZI_M7 -if SWD -vd 10 | 11 | # Start the gdb connection, without loading. 12 | gdb: 13 | arm-none-eabi-gdb -q -x debug.gdb target/thumbv7em-none-eabihf/debug/stm32h7-boot 14 | 15 | semi: 16 | socat - TCP4:localhost:2333 17 | 18 | rtt: 19 | defmt-print -e target/thumbv7em-none-eabihf/debug/stm32h7-boot --show-skipped-frames tcp 20 | # socat - TCP4:localhost:19021 21 | -------------------------------------------------------------------------------- /hello/lpc55s69/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hello-lpc55s69" 3 | version = "0.1.0" 4 | edition = "2021" 5 | description = "Hello world for lpc55s69 board" 6 | license = "Apache-2.0 or MIT" 7 | build = "build.rs" 8 | 9 | [dependencies] 10 | cortex-m = "0.7" 11 | embedded-hal = { version = "0.2", features = ["unproven"] } 12 | lpc55-hal = { version = "0.3", path = "../../lpc55-hal" } 13 | cortex-m-rt = "0.6" 14 | panic-halt = "0.2" 15 | embedded-time = "0.12.1" 16 | cortex-m-semihosting = { version = "0.5.0", features = ["jlink-quirks"] } 17 | panic-semihosting = { version = "0.5.0", features = ["jlink-quirks"] } 18 | -------------------------------------------------------------------------------- /boot/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "boot" 3 | version = "0.1.0" 4 | edition = "2021" 5 | documentation = "rust-embedded bootlaoder" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | asraw = { version = "0.1.0", path = "../asraw", default-features = false } 11 | heapless = "0.7.16" 12 | sha2 = { version = "0.10.8", default-features = false } 13 | storage = { version = "0.1.0", path = "../storage", default-features = false } 14 | 15 | [dev-dependencies] 16 | simflash = { version = "0.1.0", path = "../simflash" } 17 | 18 | [features] 19 | default = ["std"] 20 | std = ["asraw/std", "sha2/std", "storage/std"] 21 | -------------------------------------------------------------------------------- /boards/lpc55s69/jlink.gdb: -------------------------------------------------------------------------------- 1 | # Debug using gdb 2 | 3 | set history save on 4 | set confirm off 5 | 6 | # find commit-hash using `rustc -Vv` 7 | set substitute-path /rustc/cc66ad468955717ab92600c770da8c1601a4ff33 \ 8 | /home/davidb/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust 9 | 10 | target extended-remote :2331 11 | load 12 | monitor reset 13 | 14 | monitor semihosting enable 15 | # monitor semihosting breakOnError 16 | # monitor semihosting IOClient 3 17 | 18 | # Load the target image with the signed version of the image: 19 | restore ../../hello/lpc55s69/signed.bin binary 0x20000 20 | 21 | # To debug the target application, replace the symbols with these 22 | # file ../../hello/lpc55s69/target/thumbv8m.main-none-eabi/debug/hello-lpc55s69 23 | 24 | # b main 25 | # b lpc55_hal::drivers::clocks::ClockRequirements::configure 26 | 27 | # continue 28 | -------------------------------------------------------------------------------- /boards/stm32h745/jlink.gdb: -------------------------------------------------------------------------------- 1 | # Debug using gdb 2 | 3 | set history save on 4 | set confirm off 5 | 6 | # find commit-hash using `rustc -Vv` 7 | set substitute-path /rustc/cc66ad468955717ab92600c770da8c1601a4ff33 \ 8 | /home/davidb/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust 9 | 10 | target extended-remote :2331 11 | load 12 | monitor reset 13 | 14 | # monitor semihosting enable 15 | # monitor semihosting breakOnError 16 | # monitor semihosting IOClient 3 17 | 18 | # Load the target image with the signed version of the image: 19 | # restore ../../hello/lpc55s69/signed.bin binary 0x20000 20 | 21 | # To debug the target application, replace the symbols with these 22 | # file ../../hello/lpc55s69/target/thumbv8m.main-none-eabi/debug/hello-lpc55s69 23 | 24 | # b main 25 | # b lpc55_hal::drivers::clocks::ClockRequirements::configure 26 | 27 | # continue 28 | -------------------------------------------------------------------------------- /boards/stm32h745/debug.gdb: -------------------------------------------------------------------------------- 1 | # Debug using gdb 2 | 3 | set history save on 4 | set confirm off 5 | 6 | # find commit-hash using `rustc -Vv` 7 | set substitute-path /rustc/cc66ad468955717ab92600c770da8c1601a4ff33 \ 8 | /home/davidb/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust 9 | 10 | target extended-remote :2331 11 | 12 | #load 13 | #monitor reset 14 | 15 | # monitor semihosting enable 16 | # monitor semihosting breakOnError 17 | # monitor semihosting IOClient 3 18 | 19 | # Load the target image with the signed version of the image: 20 | # restore ../../hello/lpc55s69/signed.bin binary 0x20000 21 | 22 | # To debug the target application, replace the symbols with these 23 | # file ../../hello/lpc55s69/target/thumbv8m.main-none-eabi/debug/hello-lpc55s69 24 | 25 | # b main 26 | # b lpc55_hal::drivers::clocks::ClockRequirements::configure 27 | 28 | # continue 29 | -------------------------------------------------------------------------------- /boot/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This is a basic bootloader built for embedded rust. 2 | //! 3 | //! It supports various features. 4 | 5 | #![cfg_attr(not(any(feature = "std", test)), no_std)] 6 | 7 | mod image; 8 | mod status; 9 | 10 | pub use image::Image; 11 | pub use status::SlotInfo; 12 | 13 | type Result = core::result::Result; 14 | 15 | // Use the error kind to avoid this depending on the particular flash. 16 | #[derive(Debug)] 17 | pub enum Error { 18 | Flash(storage::Error), 19 | InvalidImage, 20 | CannotUpgrade, 21 | } 22 | 23 | /// Convert the nor flash error into our error type. 24 | impl From for Error { 25 | fn from(e: storage::Error) -> Self { 26 | Error::Flash(e) 27 | } 28 | } 29 | 30 | /// Some kinds of flash can be mapped into memory. This is needed for XIP devices. 31 | pub trait MappedFlash { 32 | /// Return the base address of this flash partition, as mapped into memory. 33 | fn get_base(&self) -> usize; 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 John Scarrott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /hello/lpc55s69/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | // extern crate panic_halt; 5 | extern crate panic_semihosting; 6 | 7 | use cortex_m_rt::entry; 8 | 9 | use embedded_hal::digital::v2::OutputPin; 10 | use hal::{drivers::pins::Level}; 11 | use lpc55_hal as hal; 12 | use embedded_time::rate::Extensions; 13 | 14 | use cortex_m_semihosting::{hprintln}; 15 | 16 | #[link_section = ".boot_header"] 17 | #[used] 18 | pub static BOOT_HEADER: [u8; 1024] = [0; 1024]; 19 | 20 | #[entry] 21 | fn main() -> ! { 22 | let hal = hal::new(); 23 | 24 | hprintln!("Hello world started"); 25 | 26 | let pins = hal::Pins::take().unwrap(); 27 | 28 | let mut anactrl = hal.anactrl; 29 | let mut pmc = hal.pmc; 30 | let mut syscon = hal.syscon; 31 | let mut gpio = hal.gpio.enabled(&mut syscon); 32 | let mut iocon = hal.iocon.enabled(&mut syscon); 33 | 34 | let clocks = hal::ClockRequirements::default() 35 | .system_frequency(50.MHz()) 36 | .configure(&mut anactrl, &mut pmc, &mut syscon) 37 | .unwrap(); 38 | let _ = clocks; 39 | 40 | let mut red = pins 41 | .pio1_6 42 | .into_gpio_pin(&mut iocon, &mut gpio) 43 | .into_output(Level::High); 44 | 45 | loop { 46 | red.set_low().unwrap(); 47 | hal::wait_at_least(300_000); 48 | red.set_high().unwrap(); 49 | hal::wait_at_least(300_000); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /boards/stm32h745/build.rs: -------------------------------------------------------------------------------- 1 | //! This build script copies the `memory.x` file from the crate root into 2 | //! a directory where the linker can always find it at build time. 3 | //! For many projects this is optional, as the linker always searches the 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you 5 | //! are using a workspace or have a more complicated build setup, this 6 | //! build script becomes required. Additionally, by requesting that 7 | //! Cargo re-run the build script whenever `memory.x` is changed, 8 | //! updating `memory.x` ensures a rebuild of the application with the 9 | //! new memory settings. 10 | 11 | use std::env; 12 | use std::fs::File; 13 | use std::io::Write; 14 | use std::path::PathBuf; 15 | 16 | fn main() { 17 | // Put `memory.x` in our output directory and ensure it's 18 | // on the linker search path. 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); 20 | File::create(out.join("memory.x")) 21 | .unwrap() 22 | .write_all(include_bytes!("memory.x")) 23 | .unwrap(); 24 | println!("cargo:rustc-link-search={}", out.display()); 25 | 26 | // By default, Cargo will re-run a build script whenever 27 | // any file in the project changes. By specifying `memory.x` 28 | // here, we ensure the build script is only re-run when 29 | // `memory.x` is changed. 30 | println!("cargo:rerun-if-changed=memory.x"); 31 | } 32 | -------------------------------------------------------------------------------- /boards/lpc55s69/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mcuboot-lpc55s69" 3 | version = "0.1.0" 4 | edition = "2021" 5 | description = "Bootloader for lpc55s69 board" 6 | license = "Apache-2.0 or MIT" 7 | build = "build.rs" 8 | 9 | [dependencies.byteorder] 10 | version = "1.5.0" 11 | default-features = false 12 | 13 | # Ask for the critical section implementation from cortex-m. This is only valid 14 | # with a single CPU running. 15 | [dependencies.cortex-m] 16 | version = "0.7" 17 | features = ["critical-section-single-core"] 18 | 19 | [dependencies] 20 | cortex-m-rt = "0.6" 21 | embedded-hal = { version = "0.2", features = ["unproven"] } 22 | lpc55-hal = { version = "0.3", path = "../../lpc55-hal" } 23 | # lpc55-hal = "0.3" 24 | panic-halt = "0.2" 25 | embedded-time = "0.12.1" 26 | 27 | cortex-m-semihosting = { version = "0.5.0", features = ["jlink-quirks"], optional = true } 28 | panic-semihosting = { version = "0.5.0", features = ["jlink-quirks"], optional = true } 29 | 30 | asraw = { version = "0.1", path = "../../asraw", default-features = false } 31 | boot = { version = "0.1", path = "../../boot", default-features = false } 32 | storage = { version = "0.1.0", path = "../../storage", default-features = false } 33 | 34 | # RTT Features 35 | defmt = { version = "0.3", optional = true } 36 | defmt-rtt = { version = "0.4", optional = true } 37 | panic-probe = { version = "0.3", optional = true, features = ["print-defmt"] } 38 | 39 | [features] 40 | default = ["semihosting"] 41 | semihosting = ["dep:cortex-m-semihosting", "dep:panic-semihosting"] 42 | rtt = ["dep:defmt", "dep:defmt-rtt", "dep:panic-probe"] 43 | -------------------------------------------------------------------------------- /boards/stm32h745/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stm32h7-boot" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT" 6 | 7 | [package.metadata.docs.rs] 8 | features = [] 9 | targets = [ "thumbv7em-none-eabihf" ] 10 | 11 | 12 | # - workspace ----------------------------------------------------------------- 13 | 14 | # TODO Workspace feature is blocked: https://github.com/rust-lang/cargo/issues/7004 15 | #[workspace] 16 | #members = [ 17 | # "testsuite" 18 | #] 19 | 20 | 21 | # - features ------------------------------------------------------------------ 22 | 23 | [features] 24 | 25 | default = ["rtt"] 26 | 27 | # Enable RTT debugging. 28 | rtt = ["dep:defmt", "dep:defmt-rtt", "dep:panic-probe"] 29 | 30 | # - dependencies -------------------------------------------------------------- 31 | 32 | [dependencies] 33 | cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 34 | cortex-m-rt = { version = "0.7.1" } 35 | fugit = "0.3.7" 36 | # nucleo-h7xx = "0.2.1" 37 | stm32h7xx-hal = { version = "0.15.0", features = [ "stm32h747cm7" ] } 38 | panic-semihosting = { version = "0.6.0" } 39 | 40 | # embedded-timeout-macros = "0.3.0" 41 | # heapless = "0.7.16" 42 | # nb = "1.0.0" 43 | # void = { version = "1.0.2", default-features = false } 44 | 45 | defmt = { version = "0.3", optional = true } 46 | defmt-rtt = { version = "0.4", optional = true } 47 | panic-probe = { version = "0.3", features = ["print-defmt"], optional = true } 48 | embedded-storage = "0.3.0" 49 | 50 | # - dev dependencies ---------------------------------------------------------- 51 | 52 | [dev-dependencies] 53 | panic-halt = "0.2.0" 54 | panic-itm = { version = "0.4.2" } 55 | panic-rtt-target = { version = "0.1.1", features = [ "cortex-m" ] } 56 | panic-semihosting = { version = "0.6.0" } 57 | rtt-target = { version = "0.3.1", features = [ "cortex-m" ] } 58 | 59 | # - profiles ------------------------------------------------------------------ 60 | 61 | [profile.dev] 62 | 63 | [profile.release] 64 | debug = true 65 | 66 | 67 | # - examples ------------------------------------------------------------------ 68 | 69 | [[example]] 70 | name = "hello" 71 | required-features = [] 72 | -------------------------------------------------------------------------------- /boot/tests/image.rs: -------------------------------------------------------------------------------- 1 | // Image testing. 2 | 3 | use std::cell::RefCell; 4 | 5 | use boot::{Image, SlotInfo}; 6 | 7 | #[test] 8 | fn image_test() { 9 | for flashes in simflash::styles::all_flashes() { 10 | let (mut main, mut upgrade) = flashes.unwrap(); 11 | 12 | let img1 = simflash::gen::GenBuilder::default() 13 | .size(71842) 14 | .seed(1) 15 | .build() 16 | .unwrap(); 17 | let img2 = simflash::gen::GenBuilder::default() 18 | .size(76173) 19 | .seed(2) 20 | .build() 21 | .unwrap(); 22 | 23 | main.install(&img1.data, 0).unwrap(); 24 | upgrade.install(&img2.data, 0).unwrap(); 25 | 26 | let main = RefCell::new(main); 27 | let upgrade = RefCell::new(upgrade); 28 | 29 | // Validate that this is a good image. 30 | let image = Image::from_flash(&main).unwrap(); 31 | image.validate().unwrap(); 32 | 33 | let uimage = Image::from_flash(&upgrade).unwrap(); 34 | uimage.validate().unwrap(); 35 | 36 | println!("---"); 37 | println!("main: {:x?}", image.header); 38 | println!("upgrade: {:x?}", uimage.header); 39 | 40 | // Compute the status area here. 41 | let main_size = image.full_image_size(); 42 | let upgrade_size = image.full_image_size(); 43 | let info = SlotInfo::from_data(main_size, &*main.borrow()); 44 | println!("info: {:x?}", info); 45 | let upgrade_info = SlotInfo::from_data(upgrade_size, &*upgrade.borrow()); 46 | println!("uinfo: {:x?}", upgrade_info); 47 | // println!("info: {:#x?}", info); 48 | let sminfo = info.status_layout(&upgrade_info).unwrap(); 49 | println!("main status: {:#x?}", sminfo); 50 | let suinfo = upgrade_info.status_layout(&info).unwrap(); 51 | println!("upgrade status: {:#x?}", suinfo); 52 | 53 | // Read the status area from each partition. 54 | let smstate = sminfo.read(&mut *main.borrow_mut()); 55 | println!("smstate: {:#x?}", smstate); 56 | let sustate = suinfo.read(&mut *upgrade.borrow_mut()); 57 | println!("sustate: {:#x?}", sustate); 58 | } 59 | todo!(); 60 | } 61 | -------------------------------------------------------------------------------- /storage/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Storage types. 2 | 3 | #![cfg_attr(not(any(feature = "std", test)), no_std)] 4 | 5 | // TODO: Do we want to use errors? 6 | 7 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 8 | pub enum Error { 9 | NotAligned, 10 | OutOfBounds, 11 | NotWritten, 12 | NotErased, 13 | } 14 | 15 | pub type Result = core::result::Result; 16 | 17 | /// Read only interface into flash. 18 | pub trait ReadFlash { 19 | /// What is the read size (alignment and size multiple). 20 | fn read_size(&self) -> usize; 21 | fn read(&mut self, offset: usize, bytes: &mut [u8]) -> Result<()>; 22 | fn capacity(&self) -> usize; 23 | } 24 | 25 | /// Flash that can be written to. 26 | pub trait Flash: ReadFlash { 27 | /// Write size (alignment and size multiple). 28 | fn write_size(&self) -> usize; 29 | /// Erase size (alignment and size multiple). 30 | fn erase_size(&self) -> usize; 31 | 32 | fn erase(&mut self, from: usize, to: usize) -> Result<()>; 33 | fn write(&mut self, offset: usize, bytes: &[u8]) -> Result<()>; 34 | } 35 | 36 | // Utilities taken from embedded-storage for validating arguments. 37 | pub fn check_read( 38 | flash: &T, 39 | offset: usize, 40 | length: usize, 41 | ) -> Result<()> { 42 | check_slice(flash, flash.read_size(), offset, length) 43 | } 44 | 45 | pub fn check_erase( 46 | flash: &T, 47 | from: usize, 48 | to: usize, 49 | ) -> Result<()> { 50 | if from > to || to > flash.capacity() { 51 | return Err(Error::OutOfBounds); 52 | } 53 | if from % flash.erase_size() != 0 || to % flash.erase_size() != 0 { 54 | return Err(Error::NotAligned); 55 | } 56 | Ok(()) 57 | } 58 | 59 | pub fn check_write( 60 | flash: &T, 61 | offset: usize, 62 | length: usize, 63 | ) -> Result<()> { 64 | check_slice(flash, flash.write_size(), offset, length) 65 | } 66 | 67 | pub fn check_slice( 68 | flash: &T, 69 | align: usize, 70 | offset: usize, 71 | length: usize, 72 | ) -> Result<()> { 73 | if length > flash.capacity() || offset > flash.capacity() - length { 74 | return Err(Error::OutOfBounds); 75 | } 76 | if offset % align != 0 || length % align != 0 { 77 | return Err(Error::NotAligned); 78 | } 79 | Ok(()) 80 | } 81 | -------------------------------------------------------------------------------- /boards/stm32h745/memory.x: -------------------------------------------------------------------------------- 1 | /** 2 | * See: https://github.com/stm32-rs/stm32h7xx-hal/blob/master/memory.x 3 | * https://www.st.com/resource/en/reference_manual/dm00176879-stm32h745-755-and-stm32h747-757-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf 4 | */ 5 | 6 | MEMORY 7 | { 8 | SRAM1 : ORIGIN = 0x30000000, LENGTH = 128K /* 32-bit AHB bus matrix, D2 domain */ 9 | SRAM2 : ORIGIN = 0x30020000, LENGTH = 128K /* 32-bit AHB bus matrix, D2 domain */ 10 | SRAM3 (RW) : ORIGIN = 0x30040000, LENGTH = 32K /* 32-bit AHB bus matrix, D2 domain */ 11 | SRAM4 (RW) : ORIGIN = 0x38000000, LENGTH = 64K /* 32-bit AHB bus matrix, D3 domain */ 12 | BSRAM : ORIGIN = 0x38800000, LENGTH = 4K /* 32-bit AHB bus matrix, D3 domain */ 13 | AXISRAM (RWX) : ORIGIN = 0x24000000, LENGTH = 512K /* 64-bit AXI bus matrix, D1 domain */ 14 | DTCMRAM (RWX) : ORIGIN = 0x20000000, LENGTH = 128K /* 64-bit AXI bus matrix, D1 domain */ 15 | FLASH2 (RX) : ORIGIN = 0x08100000, LENGTH = 1M /* 64-bit AXI bus matrix, D1 domain */ 16 | FLASH1 (RX) : ORIGIN = 0x08000000, LENGTH = 1M /* 64-bit AXI bus matrix, D1 domain */ 17 | ITCMRAM (RWX) : ORIGIN = 0x00000000, LENGTH = 64K /* 64-bit AXI bus matrix, D1 domain */ 18 | } 19 | 20 | /* stm32h7xx-hal uses a PROVIDE that expects RAM and FLASH symbols to exist */ 21 | REGION_ALIAS(RAM, DTCMRAM); 22 | REGION_ALIAS(FLASH, FLASH1); 23 | 24 | /* The location of the stack can be overridden using the 25 | `_stack_start` symbol. Place the stack at the end of RAM */ 26 | _stack_start = ORIGIN(RAM) + LENGTH(RAM); 27 | 28 | SECTIONS 29 | { 30 | .itcmram : ALIGN(4) { 31 | *(.itcmram .itcmram.*); 32 | . = ALIGN(4); 33 | } > ITCMRAM 34 | 35 | .dtcmram : ALIGN(4) { 36 | *(.dtcmram .dtcmram.*); 37 | . = ALIGN(4); 38 | } > DTCMRAM 39 | 40 | .axisram : ALIGN(8) { 41 | *(.axisram .axisram.*); 42 | . = ALIGN(8); 43 | } > AXISRAM 44 | 45 | /* The SRAM1 and SRAM2 section are commonly used as the stack and 46 | heap for the CM4 core in dualcore versions and should thus not 47 | be used in examples */ 48 | 49 | .sram3 (NOLOAD) : ALIGN(4) { 50 | *(.sram3 .sram3.*); 51 | . = ALIGN(4); 52 | } > SRAM3 53 | 54 | .sram4 (NOLOAD) : ALIGN(4) { 55 | *(.sram4 .sram4.*); 56 | . = ALIGN(4); 57 | } > SRAM4 58 | }; 59 | -------------------------------------------------------------------------------- /asraw/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! AsRaw provides a safe way to view a structure as its bytes, and an unsafe 2 | //! way to have this as a mutable view. Generally, this is safe and meaningful 3 | //! for structures that are repr(C). `as_mut_raw` is only safe in this case. 4 | 5 | #![cfg_attr(not(any(feature = "std", test)), no_std)] 6 | 7 | use core::{mem, slice}; 8 | 9 | pub trait AsRaw : Sized { 10 | fn as_raw(&self) -> &[u8] { 11 | unsafe { 12 | slice::from_raw_parts(self as *const _ as *const u8, 13 | mem::size_of::()) 14 | } 15 | } 16 | } 17 | 18 | /// Provide a view into a structure. This is an unsafe trait, because, in 19 | /// general, it isn't safe to interpret arbitrary bytes as another type. 20 | /// However, if the struct is `repr(C)`, and all types used are valid for all 21 | /// possible values, this will be safe. 22 | pub unsafe trait AsMutRaw : Sized { 23 | fn as_mut_raw(&mut self) -> &mut [u8] { 24 | unsafe { 25 | slice::from_raw_parts_mut(self as *mut _ as *mut u8, 26 | mem::size_of::()) 27 | } 28 | } 29 | } 30 | 31 | #[cfg(test)] 32 | mod tests { 33 | use super::*; 34 | 35 | #[derive(Debug, Default, Eq, PartialEq)] 36 | #[repr(C)] 37 | struct Item { 38 | a: u32, 39 | b: u8, 40 | c: u16, 41 | } 42 | 43 | impl AsRaw for Item {} 44 | unsafe impl AsMutRaw for Item {} 45 | 46 | #[test] 47 | fn as_raw() { 48 | let a = Item { 49 | a: 0x12345678, 50 | b: 0x54, 51 | c: 0xabcd, 52 | }; 53 | let raw_a = a.as_raw(); 54 | // We don't know our endianness, so make sure at least one of these is true. 55 | assert!(&raw_a[0..4] == &[0x78, 0x56, 0x34, 0x12] || 56 | &raw_a[0..4] == &[0x12, 0x34, 0x56, 0x78]); 57 | // There are some padding assumptions, which should be true on most 58 | // modern architectures. 59 | assert!(&raw_a[6..8] == &[0xab, 0xcd] || 60 | &raw_a[6..8] == &[0xcd, 0xab]); 61 | assert_eq!(raw_a[4], 0x54); 62 | } 63 | 64 | #[test] 65 | fn as_raw_mut() { 66 | let mut a = Item::default(); 67 | { 68 | let raw = a.as_mut_raw(); 69 | raw.copy_from_slice(&[0x12, 0x34, 0x56, 0x78, 0x54, 0xde, 0xab, 0xcd]); 70 | } 71 | let big = Item { 72 | a: 0x12345678, 73 | b: 0x54, 74 | c: 0xabcd, 75 | }; 76 | let little = Item { 77 | a: 0x78563412, 78 | b: 0x54, 79 | c: 0xcdab, 80 | }; 81 | // Note that the padding is filled in, and we assume the derived Eq only 82 | // checks the defined fields. 83 | assert!(a == big || a == little); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /boards/stm32h745/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | // use panic_semihosting as _; 5 | use panic_probe as _; 6 | use defmt_rtt as _; 7 | use defmt::{warn, info}; 8 | 9 | use hal::{rcc::PllConfigStrategy, flash::UnlockedFlashBank}; 10 | use hal::pac; 11 | use hal::flash::FlashExt; 12 | use hal::gpio::GpioExt; 13 | use hal::pwr::PwrExt; 14 | use hal::rcc::RccExt; 15 | use fugit::RateExtU32; 16 | use embedded_storage::nor_flash::{NorFlash, ReadNorFlash}; 17 | 18 | use stm32h7xx_hal as hal; 19 | 20 | #[cortex_m_rt::entry] 21 | fn main() -> ! { 22 | let dp = pac::Peripherals::take().unwrap(); 23 | 24 | // - power & clocks ------------------------------------------------------- 25 | 26 | let pwr = dp.PWR.constrain(); 27 | let pwrcfg = pwr.smps().vos0(&dp.SYSCFG).freeze(); 28 | let ccdr = dp 29 | .RCC 30 | .constrain() 31 | .pll1_strategy(PllConfigStrategy::Iterative) // pll1 drives system clock 32 | .sys_ck(480.MHz()) // system clock @ 480 MHz 33 | .freeze(pwrcfg, &dp.SYSCFG); 34 | 35 | // - pins ----------------------------------------------------------------- 36 | 37 | let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB); 38 | let mut led_user = gpiob.pb14.into_push_pull_output(); 39 | led_user.set_low(); 40 | 41 | warn!("Running"); 42 | info!("Dual bank? {}", dp.FLASH.dual_bank()); 43 | // - Flash memory. 44 | let (mut flash1, mut flash2) = dp.FLASH.split(); 45 | info!("Capacity1: 0x{:x}", flash1.len()); 46 | // info!("Capacity2: 0x{:x}", flash2.len()); 47 | 48 | if let Some(ref mut f2) = flash2 { 49 | info!("Capacity2: 0x{:x}", f2.len()); 50 | } 51 | 52 | // Erase a ways in on bank 2. 53 | { 54 | let mut f = flash1.unlocked(); 55 | let esize = ::ERASE_SIZE; 56 | let wsize = ::WRITE_SIZE; 57 | info!("Erase size: {}", esize); 58 | info!("Write size: {}", wsize); 59 | f.erase(0x40000, 0x40000).unwrap(); 60 | 61 | // Write a boring pattern. 62 | let mut buf = [0u8; 128]; 63 | for i in 0..128 { 64 | buf[i as usize] = i; 65 | } 66 | f.write(0x40000, &buf).unwrap(); 67 | } 68 | info!("Address of flash: 0x{:x}", flash1.address()); 69 | 70 | // Fault. 71 | // let _ = unsafe { *(0x0040_0000 as *const u32) }; 72 | 73 | // - main loop ------------------------------------------------------------ 74 | 75 | loop { 76 | loop { 77 | led_user.toggle(); 78 | for _ in 0..1 { 79 | // cortex_m::asm::delay(480_000_000); 80 | cortex_m::asm::delay(100_000_000); 81 | } 82 | } 83 | } 84 | } 85 | 86 | // Make this a little easier to debug. 87 | #[inline(never)] 88 | fn show() { 89 | warn!("Show what is happening"); 90 | } 91 | -------------------------------------------------------------------------------- /simflash/src/gen.rs: -------------------------------------------------------------------------------- 1 | //! Image generation. 2 | 3 | use std::{fs::{File, self}, io::Write, process::{Command, Stdio}}; 4 | 5 | use rand::{SeedableRng, RngCore}; 6 | use rand_xoshiro::Xoshiro256Plus; 7 | 8 | use anyhow::{Result, anyhow}; 9 | use temp_dir::TempDir; 10 | 11 | pub struct GeneratedImage { 12 | pub data: Vec, 13 | } 14 | 15 | pub struct GenBuilder { 16 | /// Size of the zeroed header. 17 | header_size: usize, 18 | /// Total size of the image, not counting the TLV. 19 | size: usize, 20 | /// Seed for the PRNG 21 | seed: usize, 22 | /// Version 23 | version: String, 24 | } 25 | 26 | impl Default for GenBuilder { 27 | fn default() -> Self { 28 | GenBuilder { 29 | header_size: 256, 30 | size: 76_137, 31 | seed: 1, 32 | version: "0.1.0".to_string(), 33 | } 34 | } 35 | } 36 | 37 | impl GenBuilder { 38 | pub fn size(&mut self, size: usize) -> &mut Self { 39 | self.size = size; 40 | self 41 | } 42 | 43 | pub fn seed(&mut self, seed: usize) -> &mut Self { 44 | self.seed = seed; 45 | self 46 | } 47 | 48 | pub fn build(&self) -> Result { 49 | let mut rng = Xoshiro256Plus::seed_from_u64(self.seed as u64); 50 | let mut input = vec![0u8; self.size]; 51 | rng.fill_bytes(&mut input); 52 | 53 | // The header is required to be zeros, so just fill that in. 54 | input[..self.header_size].fill(0); 55 | 56 | let tmp = TempDir::new()?; 57 | 58 | let src = tmp.path().join("image.bin"); 59 | let dest = tmp.path().join("image-signed.bin"); 60 | 61 | File::create(&src)?.write_all(&input)?; 62 | 63 | // Run imgtool. 64 | let mut cmd = Command::new("imgtool"); 65 | cmd.arg("sign"); 66 | 67 | cmd.arg("--header-size"); 68 | cmd.arg(&format!("{}", self.header_size)); 69 | 70 | cmd.arg("-v"); 71 | cmd.arg(&self.version); 72 | 73 | // This can be removed in very recent versions. 74 | cmd.arg("--align"); 75 | cmd.arg("4"); 76 | 77 | // TODO: Figure this out from the flash? 78 | cmd.arg("--slot-size"); 79 | cmd.arg(format!("{}", 128*1024)); 80 | 81 | cmd.arg(&src); 82 | cmd.arg(&dest); 83 | 84 | cmd.stdin(Stdio::null()); 85 | 86 | let status = cmd.status()?; 87 | if !status.success() { 88 | return Err(anyhow!("Unable to run imgtool: {}", status)); 89 | } 90 | 91 | let data = fs::read(&dest)?; 92 | 93 | Ok(GeneratedImage { data }) 94 | } 95 | } 96 | 97 | #[cfg(test)] 98 | mod tester { 99 | use std::cell::RefCell; 100 | use boot::Image; 101 | 102 | use crate::styles; 103 | 104 | use super::GenBuilder; 105 | 106 | #[test] 107 | fn test_gen() { 108 | let img = GenBuilder::default() 109 | .build() 110 | .unwrap(); 111 | let mut flash = styles::LPC_MAIN.build().unwrap(); 112 | flash.install(&img.data, 0).unwrap(); 113 | let flash = RefCell::new(flash); 114 | let image = Image::from_flash(&flash).unwrap(); 115 | image.validate().unwrap(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MCUboot - In Rust 2 | 3 | This project is the beginnings of a fresh implementation of MCUboot in Rust. At 4 | this point, it implements SHA256 image verification, booting a chained image, 5 | and works on the LPC55S69 LPCXpresso development, using the lp55-hal crate. 6 | This is more a proof of concept. 7 | 8 | Some things that are implemented: 9 | 10 | - The boot code lives in its own crate. This supports `cargo test` to perform 11 | some unit testing (which is incomplete). When built with 'std' enabled, the 12 | crate prints various pieces of information out, and is useful for debuggin. 13 | - The boot crate can be used `no_std`, and has no diagnostics, and returns 14 | very simple error codes. 15 | - `boards/lpc55s69` contains a build of a bootloader using the boot crate. 16 | Upon successfully validaing an image, it will chain boot to that crate. 17 | - `hello/lpc55s69` contains a simple hello/blinky application to demonstrate 18 | the bootloader. The signed version can be placed in the appropriate slot to 19 | test the bootloader. 20 | 21 | Things that still need to be done: 22 | 23 | - Other types of verification, such as signatures. 24 | - Upgrades. The main motivation of this project is to develop a new swap 25 | algorithm and status storage that is appropriate for large-write devices 26 | (hence the LPC55S69). 27 | - Everything else. MCUboot has a lot of other functionality. 28 | - Broader support. Probably worth adding at least one other board to work to 29 | generalize the board support to make these support files minimal. 30 | - Zephyr support. Related to getting Rust to work on Zephyr would make this 31 | an ideal application of that. 32 | 33 | Some issues with the LPC55S69 specifically: 34 | 35 | - There are several issue with the tip version, and some of the other 36 | dependencies I use. This uses a submodule with a fork of the lpc55-hal 37 | crate to address these issues. 38 | - The HW SHA256 engine doesn't compile, and rather than fix this at this time, 39 | just replace the offending code with a `todo!()`. When adding the idea of 40 | crypto providers to `boot`, this can be addressed to add support for the 41 | LPC's hardware crypto support. 42 | - Clock initialization can only be done once. Until addressed, the boot main 43 | doesn't initialize any clocks. It appears that clock initialization is 44 | leaving the CPU connected to the PLL while trying to program it. 45 | 46 | ## How to try it. 47 | 48 | In order to test this out, you will currently need an LPCXpresso55S69 49 | development board. I was able to get it to work with the jlink firmware. 50 | 51 | - Install the jlink tools for your platform. 52 | - Install the Arm toolchain gdb. On ubuntu, this is `gdb-arm-none-eabi` 53 | - Install socat. 54 | - Make sure you have rust installed. Rustup is the easiest way to do this. 55 | - Install imgtool from the main mcuboot project: 56 | ``` 57 | $ pip install -u imgtool 58 | ``` 59 | - Install the thumbv8m.main-none-eabi target if you haven't 60 | ``` 61 | $ rustup target add thumbv8m.main-none-eabi 62 | ``` 63 | - Build the 'hello world' application. 64 | ``` 65 | $ cd hello/lpc55s69 66 | $ cargo build 67 | $ make sign 68 | $ cd ../.. 69 | ``` 70 | this should generate a `signed.bin` which is a signed version. 71 | - Test the boot code. 72 | ``` 73 | $ cd boot 74 | $ cargo test 75 | $ cd .. 76 | ``` 77 | note that, at this time, these tests are incomplete, and actually fail to print 78 | out what it is doing. 79 | - Test on the target 80 | You'll need three windows for this. Each window should be in the 81 | `boards/lpc55s69` directory. 82 | 83 | In one window, start the jlink gdb server: 84 | ``` 85 | $ make jlink 86 | ``` 87 | In another window, run socat to dump semihosting messages. 88 | ``` 89 | $ make semi 90 | ``` 91 | And in the third window, start gdb. 92 | ``` 93 | $ cargo run 94 | ``` 95 | This should load both the executable under test, and the signed.bin image 96 | created earlier. 97 | -------------------------------------------------------------------------------- /simflash/src/styles.rs: -------------------------------------------------------------------------------- 1 | //! Flash styles 2 | //! 3 | //! Various microcontrollers have various types of flash memories available to them. 4 | 5 | use crate::SimFlash; 6 | use crate::Result; 7 | 8 | /// The configuration of a single flash area. 9 | pub struct AreaLayout { 10 | pub read_size: usize, 11 | pub write_size: usize, 12 | pub erase_size: usize, 13 | pub sectors: usize, 14 | } 15 | 16 | impl AreaLayout { 17 | pub fn build(&self) -> Result { 18 | SimFlash::new( 19 | self.read_size, 20 | self.write_size, 21 | self.erase_size, 22 | self.sectors, 23 | ) 24 | } 25 | } 26 | 27 | /// STM32F4-style. 28 | /// These devices have a fairly small number of relatively large sectors. Note 29 | /// that if you wish to use MCUboot across an area where the sector sizes 30 | /// differ, MCUboot will see the smaller sectors as if they were a larger sector 31 | /// of whatever the largest size within the region is. 32 | /// This tends to stress the extreme in terms of small, as the image and the 33 | /// status area must fit entirely within the seconary area, which is a single sector. 34 | pub static STM32F_MAIN: AreaLayout = AreaLayout { 35 | read_size: 1, 36 | write_size: 8, 37 | erase_size: 128*1024, 38 | sectors: 2, 39 | }; 40 | pub static STM32F_UPGRADE: AreaLayout = AreaLayout { 41 | read_size: 1, 42 | write_size: 8, 43 | erase_size: 128*1024, 44 | sectors: 1, 45 | }; 46 | 47 | /// K64-style. 48 | /// These devices have small uniform sectors. 49 | pub static K64_MAIN: AreaLayout = AreaLayout { 50 | read_size: 1, 51 | write_size: 8, 52 | erase_size: 4*1024, 53 | sectors: 128/4 + 1, 54 | }; 55 | pub static K64_UPGRADE: AreaLayout = AreaLayout { 56 | read_size: 1, 57 | write_size: 8, 58 | erase_size: 4*1024, 59 | sectors: 128/4 + 1, 60 | }; 61 | 62 | /// External flash configuration. The external partition is the same size, so 63 | /// the image needs to have room. The external flash has a large write alignment. 64 | pub static EXT_MAIN: AreaLayout = AreaLayout { 65 | read_size: 1, 66 | write_size: 4, 67 | erase_size: 4*1024, 68 | sectors: 128/4, 69 | }; 70 | pub static EXT_UPGRADE: AreaLayout = AreaLayout { 71 | read_size: 1, 72 | write_size: 256, 73 | erase_size: 4*1024, 74 | sectors: 128/4, 75 | }; 76 | 77 | /// Page-style devices. Based on the LPC55S69. 78 | pub static LPC_MAIN: AreaLayout = AreaLayout { 79 | read_size: 1, 80 | write_size: 512, 81 | erase_size: 512, 82 | sectors: 128*2, 83 | }; 84 | pub static LPC_UPGRADE: AreaLayout = AreaLayout { 85 | read_size: 1, 86 | write_size: 512, 87 | erase_size: 512, 88 | sectors: 128*2, 89 | }; 90 | 91 | /// Another large write, based on the STM32H745 92 | pub static STM32H_MAIN: AreaLayout = AreaLayout { 93 | read_size: 1, 94 | write_size: 32, 95 | erase_size: 128*1024, 96 | sectors: 4, 97 | }; 98 | pub static STM32H_UPGRADE: AreaLayout = AreaLayout { 99 | read_size: 1, 100 | write_size: 32, 101 | erase_size: 128*1024, 102 | sectors: 3, 103 | }; 104 | 105 | /// All of the flash devices, as pairs. 106 | pub static ALL_FLASHES: [(&'static AreaLayout, &'static AreaLayout); 5] = [ 107 | (&STM32F_MAIN, &STM32F_UPGRADE), 108 | (&K64_MAIN, &K64_UPGRADE), 109 | (&EXT_MAIN, &EXT_UPGRADE), 110 | (&LPC_MAIN, &LPC_UPGRADE), 111 | (&STM32H_MAIN, &STM32H_UPGRADE), 112 | ]; 113 | 114 | /// An iterator that returns each of the device pairs on each iteration. 115 | pub fn all_flashes() -> impl Iterator> { 116 | ALL_FLASHES.iter().map(|(a, b)| { 117 | let a = match a.build() { 118 | Ok(a) => a, 119 | Err(e) => return Err(e), 120 | }; 121 | let b = match b.build() { 122 | Ok(b) => b, 123 | Err(e) => return Err(e), 124 | }; 125 | Ok((a, b)) 126 | }) 127 | } 128 | -------------------------------------------------------------------------------- /boards/lpc55s69/src/flash.rs: -------------------------------------------------------------------------------- 1 | //! LPC55S6x flash driver. 2 | //! 3 | //! Replacement flash driver from the one in the hal. This attempts to do a few 4 | //! basic things: 5 | //! 6 | //! - Implement embedded_storage::nor_flash::ReadNorFlash and NorFlash 7 | //! interfaces 8 | //! - Implement a robust read that will return an error instead of busfaulting 9 | //! on unprogrammed data. 10 | //! 11 | //! To use this driver, you should release the FLASH PAC from the hal's driver. 12 | //! 13 | //! let flash = hal.flash.release(); 14 | //! let fl = flash::LpcFlash::new(flash); 15 | 16 | use core::cell::RefCell; 17 | 18 | use boot::MappedFlash; 19 | use storage::ReadFlash; 20 | use hal::raw::FLASH; 21 | use lpc55_hal as hal; 22 | 23 | pub use storage::Error; 24 | 25 | // use crate::hprintln; 26 | 27 | type Result = core::result::Result; 28 | 29 | pub struct LpcFlash { 30 | raw: RefCell, 31 | } 32 | 33 | const LPC_FLASH_BASE: usize = 0; 34 | const LPC_FLASH_SIZE: usize = 630 * 1024; 35 | 36 | // Flash for the entire device. 37 | impl LpcFlash { 38 | pub fn new(raw: hal::raw::FLASH) -> LpcFlash { 39 | LpcFlash { raw: RefCell::new(raw) } 40 | } 41 | 42 | pub fn partition(&self, base: usize, length: usize) -> Result { 43 | LpcPartition::new(self, base, length) 44 | } 45 | } 46 | 47 | // A single flash partition. References the parent. 48 | pub struct LpcPartition<'a> { 49 | flash: &'a LpcFlash, 50 | base: usize, 51 | length: usize, 52 | } 53 | 54 | impl<'a> LpcPartition<'a> { 55 | pub fn new(flash: &'a LpcFlash, base: usize, length: usize) -> Result { 56 | if length == 0 { 57 | return Err(Error::OutOfBounds); 58 | } 59 | // This wouldn't be right if the flash was at the end of the address 60 | // space. But as such, it does prevent overflow. It is safe to subtract 61 | // one because we checked that above. 62 | let end = match base.checked_add(length) { 63 | Some(e) => e - 1, 64 | None => return Err(Error::OutOfBounds), 65 | }; 66 | // No overflow check, as these are consts. 67 | let self_range = LPC_FLASH_BASE .. LPC_FLASH_BASE + LPC_FLASH_SIZE; 68 | if !(self_range.contains(&base) && self_range.contains(&end)) { 69 | return Err(Error::OutOfBounds); 70 | } 71 | 72 | Ok(LpcPartition { flash, base, length }) 73 | } 74 | } 75 | 76 | impl<'a> ReadFlash for LpcPartition<'a> { 77 | // We allow arbitrary alignment of reads. 78 | fn read_size(&self) -> usize { 79 | 1 80 | } 81 | 82 | fn capacity(&self) -> usize { 83 | self.length 84 | } 85 | 86 | fn read(&mut self, offset: usize, buf: &mut [u8]) -> Result<()> { 87 | storage::check_read(self, offset, buf.len())?; 88 | 89 | let offset = offset.checked_add(self.base).ok_or(Error::OutOfBounds)?; 90 | 91 | // Validate that the entire range has been written. 92 | let end = offset + buf.len(); 93 | let mut bpage = offset & !511; 94 | while bpage < end { 95 | // hprintln!("Read check: 0x{:x}", bpage); 96 | if !read_check(&self.flash.raw.borrow(), bpage as u32) { 97 | // Indicate read error with Other 98 | return Err(Error::NotWritten); 99 | } 100 | bpage += 512; 101 | } 102 | 103 | // Copy the data. 104 | let slice = unsafe { 105 | core::slice::from_raw_parts(offset as *const u8, buf.len()) 106 | }; 107 | buf.copy_from_slice(slice); 108 | 109 | Ok(()) 110 | } 111 | } 112 | 113 | impl<'a> MappedFlash for LpcPartition<'a> { 114 | fn get_base(&self) -> usize { 115 | LPC_FLASH_BASE + self.base 116 | } 117 | } 118 | 119 | fn read_check(flash: &FLASH, addr: u32) -> bool { 120 | // Wait for anything to complete, and clear status. 121 | /* 122 | while flash.int_status.read().done().bit_is_clear() { 123 | } 124 | */ 125 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 126 | 127 | flash.starta.write(|w| unsafe{w.bits(addr >> 4)}); 128 | flash.stopa.write(|w| unsafe{w.bits(addr >> 4)}); 129 | flash.cmd.write(|w| unsafe{w.bits(6)}); 130 | while flash.int_status.read().done().bit_is_clear() { 131 | } 132 | 133 | let good = flash.int_status.read().fail().bit_is_clear(); 134 | 135 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 136 | 137 | good 138 | } 139 | -------------------------------------------------------------------------------- /simflash/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Simulated flash 2 | //! 3 | //! The NOR-type flashes used in microcontrollers differs quite a bit in terms 4 | //! of capabilities provided. This simulator attempts to capture the diversity 5 | //! of these devices. 6 | //! 7 | //! We make these simulated flash devices available via the embedded-flash 8 | //! traits, at least some of the NOR-specific ones, notably ReadNorFlash and 9 | //! NorFlash. Most of the rest of the traits are fairly useless as they tend to 10 | //! abstract the funcionality of the device and make it impossible to use the 11 | //! devices robustly. 12 | //! 13 | //! The NorFlash defines a READ_SIZE, an ERASE_SIZE, and a WRITE_SIZE. We 14 | //! require that the erase size be a multiple of the WRITE_SIZE (they can be the 15 | //! same). At this point in time, the READ_SIZE is always 1. There are a 16 | //! couple of different families of devices that are common: 17 | //! 18 | //! - Old style: ERASE_SIZE is 4k-128k, WRITE_SIZE is typically 1-8, sometimes 19 | //! as much as 16 or 32, although these might need to be considered a different 20 | //! class of device. 21 | //! - Large write: ERASE_SIZE is 128k, WRITE_SIZE is 32. Large to write, but 22 | //! also large erase sizes. Might be best handled as above. 23 | //! - Paged: ERASE_SIZE is 512, WRITE_SIZE is 512. The write size is much 24 | //! larger than thye others, but the smaller erases allow us to treat the device 25 | //! more like blocks. 26 | 27 | use std::ops::Range; 28 | 29 | pub mod styles; 30 | pub mod gen; 31 | 32 | use storage::{ 33 | Error, Flash, ReadFlash, Result, 34 | }; 35 | 36 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 37 | enum PageState { 38 | Erased, 39 | Written, 40 | Unknown, 41 | } 42 | 43 | pub struct SimFlash { 44 | read_size: usize, 45 | write_size: usize, 46 | erase_size: usize, 47 | data: Vec, 48 | page_state: Vec 49 | } 50 | 51 | impl SimFlash { 52 | // Some terminology: 53 | // - Page - the unit written 54 | // - Sector - the unit erased 55 | 56 | fn pages_per_sector(&self) -> usize { 57 | self.erase_size / self.write_size 58 | } 59 | 60 | /// Create a new simulated flash device. The size will be based on the 61 | /// given number of pages. 62 | pub fn new(read_size: usize, write_size: usize, erase_size: usize, sectors: usize) -> Result { 63 | // TODO: Ideally, these would be checked at compile time. 64 | assert!(write_size <= erase_size); 65 | assert!(erase_size % write_size == 0); 66 | 67 | let pages_per_sector = erase_size / write_size; 68 | 69 | let page_state = vec![PageState::Unknown; sectors * pages_per_sector]; 70 | let data = vec![0xff; sectors * erase_size]; 71 | Ok(SimFlash {read_size, write_size, erase_size, data, page_state}) 72 | } 73 | 74 | /// Given a byte value, return what page contains that byte. 75 | fn page_of(&self, offset: usize) -> usize { 76 | offset / self.write_size 77 | } 78 | 79 | /// Given a 'from' and 'to' value in bytes (a range), return a range over 80 | /// the page affected. 81 | fn pages(&self, from: usize, to: usize) -> Range { 82 | self.page_of(from) .. self.page_of(to - 1) + 1 83 | } 84 | 85 | /// Install a given image into the flash at the given offset. For now, the 86 | /// offset must be aligned. 87 | pub fn install(&mut self, bytes: &[u8], offset: usize) -> Result<()> { 88 | // Set this to past the device, so that we will always try erasing. 89 | assert_eq!(offset as usize % self.erase_size, 0); 90 | 91 | let mut last_erased = self.page_state.len() / self.pages_per_sector(); 92 | let mut pos = 0; 93 | let mut buf = vec![0u8; self.write_size]; 94 | while pos < bytes.len() { 95 | let dev_pos = pos + offset as usize; 96 | let dev_sector = dev_pos / self.erase_size; 97 | if dev_sector != last_erased { 98 | self.erase(dev_sector * self.erase_size, 99 | (dev_sector + 1) * self.erase_size)?; 100 | last_erased = dev_sector; 101 | } 102 | 103 | let len = self.write_size.min(bytes.len() - pos); 104 | buf.fill(0xff); 105 | buf[..len].copy_from_slice(&bytes[pos .. pos + len]); 106 | self.write(dev_pos, &buf)?; 107 | 108 | pos += self.write_size; 109 | } 110 | Ok(()) 111 | } 112 | } 113 | 114 | impl ReadFlash for SimFlash { 115 | fn read_size(&self) -> usize { 116 | self.read_size 117 | } 118 | 119 | fn capacity(&self) -> usize { 120 | self.data.len() 121 | } 122 | 123 | fn read(&mut self, offset: usize, bytes: &mut [u8]) -> Result<()> { 124 | storage::check_read(self, offset, bytes.len())?; 125 | let offset = offset as usize; 126 | 127 | for i in self.pages(offset, offset + bytes.len()) { 128 | if self.page_state[i] != PageState::Written { 129 | return Err(Error::NotWritten); 130 | } 131 | } 132 | 133 | bytes.copy_from_slice(&self.data[offset .. offset + bytes.len()]); 134 | Ok(()) 135 | } 136 | } 137 | 138 | impl Flash for SimFlash { 139 | fn write_size(&self) -> usize { 140 | self.write_size 141 | } 142 | 143 | fn erase_size(&self) -> usize { 144 | self.erase_size 145 | } 146 | 147 | fn erase(&mut self, from: usize, to: usize) -> Result<()> { 148 | storage::check_erase(self, from, to)?; 149 | 150 | for i in self.pages(from as usize, to as usize) { 151 | self.page_state[i] = PageState::Erased; 152 | } 153 | Ok(()) 154 | } 155 | 156 | fn write(&mut self, offset: usize, bytes: &[u8]) -> Result<()> { 157 | storage::check_write(self, offset, bytes.len())?; 158 | let offset = offset as usize; 159 | 160 | for i in self.pages(offset, offset + bytes.len()) { 161 | if self.page_state[i] != PageState::Erased { 162 | return Err(Error::NotErased); 163 | } 164 | } 165 | 166 | for i in self.pages(offset, offset + bytes.len()) { 167 | self.page_state[i] = PageState::Written; 168 | } 169 | 170 | self.data[offset .. offset + bytes.len()].copy_from_slice(bytes); 171 | Ok(()) 172 | } 173 | } 174 | 175 | #[test] 176 | fn test_simflash() { 177 | let mut f1 = SimFlash::new(1, 32, 128*1024, 6).unwrap(); 178 | let mut buf = [0u8; 256]; 179 | assert_eq!(f1.capacity(), 6*128*1024); 180 | assert_eq!(f1.read(0, &mut buf), Err(Error::NotWritten)); 181 | assert_eq!(f1.erase(128*1024, 256*1024), Ok(())); 182 | assert_eq!(f1.write(128*1024, &mut buf), Ok(())); 183 | 184 | buf.fill(0x42); 185 | assert_eq!(f1.read(128*1024, &mut buf), Ok(())); 186 | } 187 | -------------------------------------------------------------------------------- /boot/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.75" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 10 | 11 | [[package]] 12 | name = "asraw" 13 | version = "0.1.0" 14 | 15 | [[package]] 16 | name = "atomic-polyfill" 17 | version = "0.1.11" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" 20 | dependencies = [ 21 | "critical-section", 22 | ] 23 | 24 | [[package]] 25 | name = "autocfg" 26 | version = "1.1.0" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 29 | 30 | [[package]] 31 | name = "block-buffer" 32 | version = "0.10.4" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 35 | dependencies = [ 36 | "generic-array", 37 | ] 38 | 39 | [[package]] 40 | name = "boot" 41 | version = "0.1.0" 42 | dependencies = [ 43 | "asraw", 44 | "heapless", 45 | "sha2", 46 | "simflash", 47 | "storage", 48 | ] 49 | 50 | [[package]] 51 | name = "byteorder" 52 | version = "1.5.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 55 | 56 | [[package]] 57 | name = "cfg-if" 58 | version = "1.0.0" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 61 | 62 | [[package]] 63 | name = "cpufeatures" 64 | version = "0.2.11" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" 67 | dependencies = [ 68 | "libc", 69 | ] 70 | 71 | [[package]] 72 | name = "critical-section" 73 | version = "1.1.2" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 76 | 77 | [[package]] 78 | name = "crypto-common" 79 | version = "0.1.6" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 82 | dependencies = [ 83 | "generic-array", 84 | "typenum", 85 | ] 86 | 87 | [[package]] 88 | name = "digest" 89 | version = "0.10.7" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 92 | dependencies = [ 93 | "block-buffer", 94 | "crypto-common", 95 | ] 96 | 97 | [[package]] 98 | name = "generic-array" 99 | version = "0.14.7" 100 | source = "registry+https://github.com/rust-lang/crates.io-index" 101 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 102 | dependencies = [ 103 | "typenum", 104 | "version_check", 105 | ] 106 | 107 | [[package]] 108 | name = "getrandom" 109 | version = "0.2.10" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 112 | dependencies = [ 113 | "cfg-if", 114 | "libc", 115 | "wasi", 116 | ] 117 | 118 | [[package]] 119 | name = "hash32" 120 | version = "0.2.1" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 123 | dependencies = [ 124 | "byteorder", 125 | ] 126 | 127 | [[package]] 128 | name = "heapless" 129 | version = "0.7.16" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" 132 | dependencies = [ 133 | "atomic-polyfill", 134 | "hash32", 135 | "rustc_version", 136 | "spin", 137 | "stable_deref_trait", 138 | ] 139 | 140 | [[package]] 141 | name = "libc" 142 | version = "0.2.149" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 145 | 146 | [[package]] 147 | name = "lock_api" 148 | version = "0.4.11" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 151 | dependencies = [ 152 | "autocfg", 153 | "scopeguard", 154 | ] 155 | 156 | [[package]] 157 | name = "ppv-lite86" 158 | version = "0.2.17" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 161 | 162 | [[package]] 163 | name = "rand" 164 | version = "0.8.5" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 167 | dependencies = [ 168 | "libc", 169 | "rand_chacha", 170 | "rand_core", 171 | ] 172 | 173 | [[package]] 174 | name = "rand_chacha" 175 | version = "0.3.1" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 178 | dependencies = [ 179 | "ppv-lite86", 180 | "rand_core", 181 | ] 182 | 183 | [[package]] 184 | name = "rand_core" 185 | version = "0.6.4" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 188 | dependencies = [ 189 | "getrandom", 190 | ] 191 | 192 | [[package]] 193 | name = "rand_xoshiro" 194 | version = "0.6.0" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" 197 | dependencies = [ 198 | "rand_core", 199 | ] 200 | 201 | [[package]] 202 | name = "rustc_version" 203 | version = "0.4.0" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 206 | dependencies = [ 207 | "semver", 208 | ] 209 | 210 | [[package]] 211 | name = "scopeguard" 212 | version = "1.2.0" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 215 | 216 | [[package]] 217 | name = "semver" 218 | version = "1.0.20" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" 221 | 222 | [[package]] 223 | name = "sha2" 224 | version = "0.10.8" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 227 | dependencies = [ 228 | "cfg-if", 229 | "cpufeatures", 230 | "digest", 231 | ] 232 | 233 | [[package]] 234 | name = "simflash" 235 | version = "0.1.0" 236 | dependencies = [ 237 | "anyhow", 238 | "rand", 239 | "rand_xoshiro", 240 | "storage", 241 | "temp-dir", 242 | ] 243 | 244 | [[package]] 245 | name = "spin" 246 | version = "0.9.8" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 249 | dependencies = [ 250 | "lock_api", 251 | ] 252 | 253 | [[package]] 254 | name = "stable_deref_trait" 255 | version = "1.2.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 258 | 259 | [[package]] 260 | name = "storage" 261 | version = "0.1.0" 262 | 263 | [[package]] 264 | name = "temp-dir" 265 | version = "0.1.11" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab" 268 | 269 | [[package]] 270 | name = "typenum" 271 | version = "1.17.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 274 | 275 | [[package]] 276 | name = "version_check" 277 | version = "0.9.4" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 280 | 281 | [[package]] 282 | name = "wasi" 283 | version = "0.11.0+wasi-snapshot-preview1" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 286 | -------------------------------------------------------------------------------- /simflash/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.75" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" 10 | 11 | [[package]] 12 | name = "asraw" 13 | version = "0.1.0" 14 | 15 | [[package]] 16 | name = "atomic-polyfill" 17 | version = "0.1.11" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" 20 | dependencies = [ 21 | "critical-section", 22 | ] 23 | 24 | [[package]] 25 | name = "autocfg" 26 | version = "1.1.0" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 29 | 30 | [[package]] 31 | name = "block-buffer" 32 | version = "0.10.4" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 35 | dependencies = [ 36 | "generic-array", 37 | ] 38 | 39 | [[package]] 40 | name = "boot" 41 | version = "0.1.0" 42 | dependencies = [ 43 | "asraw", 44 | "heapless", 45 | "sha2", 46 | "storage", 47 | ] 48 | 49 | [[package]] 50 | name = "byteorder" 51 | version = "1.5.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 54 | 55 | [[package]] 56 | name = "cfg-if" 57 | version = "1.0.0" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 60 | 61 | [[package]] 62 | name = "cpufeatures" 63 | version = "0.2.11" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" 66 | dependencies = [ 67 | "libc", 68 | ] 69 | 70 | [[package]] 71 | name = "critical-section" 72 | version = "1.1.2" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 75 | 76 | [[package]] 77 | name = "crypto-common" 78 | version = "0.1.6" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 81 | dependencies = [ 82 | "generic-array", 83 | "typenum", 84 | ] 85 | 86 | [[package]] 87 | name = "digest" 88 | version = "0.10.7" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 91 | dependencies = [ 92 | "block-buffer", 93 | "crypto-common", 94 | ] 95 | 96 | [[package]] 97 | name = "generic-array" 98 | version = "0.14.7" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 101 | dependencies = [ 102 | "typenum", 103 | "version_check", 104 | ] 105 | 106 | [[package]] 107 | name = "getrandom" 108 | version = "0.2.10" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 111 | dependencies = [ 112 | "cfg-if", 113 | "libc", 114 | "wasi", 115 | ] 116 | 117 | [[package]] 118 | name = "hash32" 119 | version = "0.2.1" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 122 | dependencies = [ 123 | "byteorder", 124 | ] 125 | 126 | [[package]] 127 | name = "heapless" 128 | version = "0.7.16" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" 131 | dependencies = [ 132 | "atomic-polyfill", 133 | "hash32", 134 | "rustc_version", 135 | "spin", 136 | "stable_deref_trait", 137 | ] 138 | 139 | [[package]] 140 | name = "libc" 141 | version = "0.2.149" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 144 | 145 | [[package]] 146 | name = "lock_api" 147 | version = "0.4.11" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 150 | dependencies = [ 151 | "autocfg", 152 | "scopeguard", 153 | ] 154 | 155 | [[package]] 156 | name = "ppv-lite86" 157 | version = "0.2.17" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 160 | 161 | [[package]] 162 | name = "rand" 163 | version = "0.8.5" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 166 | dependencies = [ 167 | "libc", 168 | "rand_chacha", 169 | "rand_core", 170 | ] 171 | 172 | [[package]] 173 | name = "rand_chacha" 174 | version = "0.3.1" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 177 | dependencies = [ 178 | "ppv-lite86", 179 | "rand_core", 180 | ] 181 | 182 | [[package]] 183 | name = "rand_core" 184 | version = "0.6.4" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 187 | dependencies = [ 188 | "getrandom", 189 | ] 190 | 191 | [[package]] 192 | name = "rand_xoshiro" 193 | version = "0.6.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" 196 | dependencies = [ 197 | "rand_core", 198 | ] 199 | 200 | [[package]] 201 | name = "rustc_version" 202 | version = "0.4.0" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 205 | dependencies = [ 206 | "semver", 207 | ] 208 | 209 | [[package]] 210 | name = "scopeguard" 211 | version = "1.2.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 214 | 215 | [[package]] 216 | name = "semver" 217 | version = "1.0.20" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" 220 | 221 | [[package]] 222 | name = "sha2" 223 | version = "0.10.8" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 226 | dependencies = [ 227 | "cfg-if", 228 | "cpufeatures", 229 | "digest", 230 | ] 231 | 232 | [[package]] 233 | name = "simflash" 234 | version = "0.1.0" 235 | dependencies = [ 236 | "anyhow", 237 | "boot", 238 | "rand", 239 | "rand_xoshiro", 240 | "storage", 241 | "temp-dir", 242 | ] 243 | 244 | [[package]] 245 | name = "spin" 246 | version = "0.9.8" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 249 | dependencies = [ 250 | "lock_api", 251 | ] 252 | 253 | [[package]] 254 | name = "stable_deref_trait" 255 | version = "1.2.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 258 | 259 | [[package]] 260 | name = "storage" 261 | version = "0.1.0" 262 | 263 | [[package]] 264 | name = "temp-dir" 265 | version = "0.1.11" 266 | source = "registry+https://github.com/rust-lang/crates.io-index" 267 | checksum = "af547b166dd1ea4b472165569fc456cfb6818116f854690b0ff205e636523dab" 268 | 269 | [[package]] 270 | name = "typenum" 271 | version = "1.17.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 274 | 275 | [[package]] 276 | name = "version_check" 277 | version = "0.9.4" 278 | source = "registry+https://github.com/rust-lang/crates.io-index" 279 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 280 | 281 | [[package]] 282 | name = "wasi" 283 | version = "0.11.0+wasi-snapshot-preview1" 284 | source = "registry+https://github.com/rust-lang/crates.io-index" 285 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 286 | -------------------------------------------------------------------------------- /hello/lpc55s69/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.1.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 10 | 11 | [[package]] 12 | name = "bare-metal" 13 | version = "0.2.5" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 16 | dependencies = [ 17 | "rustc_version", 18 | ] 19 | 20 | [[package]] 21 | name = "bitfield" 22 | version = "0.13.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 25 | 26 | [[package]] 27 | name = "block-buffer" 28 | version = "0.9.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 31 | dependencies = [ 32 | "generic-array", 33 | ] 34 | 35 | [[package]] 36 | name = "cipher" 37 | version = "0.3.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 40 | dependencies = [ 41 | "generic-array", 42 | ] 43 | 44 | [[package]] 45 | name = "cortex-m" 46 | version = "0.7.7" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" 49 | dependencies = [ 50 | "bare-metal", 51 | "bitfield", 52 | "embedded-hal", 53 | "volatile-register", 54 | ] 55 | 56 | [[package]] 57 | name = "cortex-m-rt" 58 | version = "0.6.15" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "454f278bf469e2de0a4d22ea019d169d8944f86957c8207a39e3f66c32be2fc6" 61 | dependencies = [ 62 | "cortex-m-rt-macros", 63 | "r0", 64 | ] 65 | 66 | [[package]] 67 | name = "cortex-m-rt-macros" 68 | version = "0.6.15" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "c8e3aa52243e26f5922fa522b0814019e0c98fc567e2756d715dce7ad7a81f49" 71 | dependencies = [ 72 | "proc-macro2", 73 | "quote", 74 | "syn", 75 | ] 76 | 77 | [[package]] 78 | name = "cortex-m-semihosting" 79 | version = "0.3.7" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc" 82 | dependencies = [ 83 | "cortex-m", 84 | ] 85 | 86 | [[package]] 87 | name = "cortex-m-semihosting" 88 | version = "0.5.0" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" 91 | dependencies = [ 92 | "cortex-m", 93 | ] 94 | 95 | [[package]] 96 | name = "digest" 97 | version = "0.9.0" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 100 | dependencies = [ 101 | "generic-array", 102 | ] 103 | 104 | [[package]] 105 | name = "embedded-hal" 106 | version = "0.2.7" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 109 | dependencies = [ 110 | "nb 0.1.3", 111 | "void", 112 | ] 113 | 114 | [[package]] 115 | name = "embedded-time" 116 | version = "0.12.1" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" 119 | dependencies = [ 120 | "num", 121 | ] 122 | 123 | [[package]] 124 | name = "generic-array" 125 | version = "0.14.7" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 128 | dependencies = [ 129 | "typenum", 130 | "version_check", 131 | ] 132 | 133 | [[package]] 134 | name = "hello-lpc55s69" 135 | version = "0.1.0" 136 | dependencies = [ 137 | "cortex-m", 138 | "cortex-m-rt", 139 | "cortex-m-semihosting 0.5.0", 140 | "embedded-hal", 141 | "embedded-time", 142 | "lpc55-hal", 143 | "panic-halt", 144 | "panic-semihosting", 145 | ] 146 | 147 | [[package]] 148 | name = "lpc55-hal" 149 | version = "0.3.0" 150 | dependencies = [ 151 | "block-buffer", 152 | "cipher", 153 | "cortex-m", 154 | "digest", 155 | "embedded-hal", 156 | "embedded-time", 157 | "generic-array", 158 | "lpc55-pac", 159 | "nb 1.1.0", 160 | "rand_core", 161 | "usb-device", 162 | "vcell", 163 | "void", 164 | ] 165 | 166 | [[package]] 167 | name = "lpc55-pac" 168 | version = "0.4.1" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "cf1b5b32d313af526145882f5115a55177f479e9328ca667a84aaaa1ae6d65d3" 171 | dependencies = [ 172 | "cortex-m", 173 | "cortex-m-rt", 174 | "vcell", 175 | ] 176 | 177 | [[package]] 178 | name = "nb" 179 | version = "0.1.3" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 182 | dependencies = [ 183 | "nb 1.1.0", 184 | ] 185 | 186 | [[package]] 187 | name = "nb" 188 | version = "1.1.0" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 191 | 192 | [[package]] 193 | name = "num" 194 | version = "0.3.1" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" 197 | dependencies = [ 198 | "num-complex", 199 | "num-integer", 200 | "num-iter", 201 | "num-rational", 202 | "num-traits", 203 | ] 204 | 205 | [[package]] 206 | name = "num-complex" 207 | version = "0.3.1" 208 | source = "registry+https://github.com/rust-lang/crates.io-index" 209 | checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" 210 | dependencies = [ 211 | "num-traits", 212 | ] 213 | 214 | [[package]] 215 | name = "num-integer" 216 | version = "0.1.45" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 219 | dependencies = [ 220 | "autocfg", 221 | "num-traits", 222 | ] 223 | 224 | [[package]] 225 | name = "num-iter" 226 | version = "0.1.43" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" 229 | dependencies = [ 230 | "autocfg", 231 | "num-integer", 232 | "num-traits", 233 | ] 234 | 235 | [[package]] 236 | name = "num-rational" 237 | version = "0.3.2" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 240 | dependencies = [ 241 | "autocfg", 242 | "num-integer", 243 | "num-traits", 244 | ] 245 | 246 | [[package]] 247 | name = "num-traits" 248 | version = "0.2.17" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 251 | dependencies = [ 252 | "autocfg", 253 | ] 254 | 255 | [[package]] 256 | name = "panic-halt" 257 | version = "0.2.0" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" 260 | 261 | [[package]] 262 | name = "panic-semihosting" 263 | version = "0.5.6" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec" 266 | dependencies = [ 267 | "cortex-m", 268 | "cortex-m-semihosting 0.3.7", 269 | ] 270 | 271 | [[package]] 272 | name = "proc-macro2" 273 | version = "1.0.69" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 276 | dependencies = [ 277 | "unicode-ident", 278 | ] 279 | 280 | [[package]] 281 | name = "quote" 282 | version = "1.0.33" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 285 | dependencies = [ 286 | "proc-macro2", 287 | ] 288 | 289 | [[package]] 290 | name = "r0" 291 | version = "0.2.2" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" 294 | 295 | [[package]] 296 | name = "rand_core" 297 | version = "0.6.4" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 300 | 301 | [[package]] 302 | name = "rustc_version" 303 | version = "0.2.3" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 306 | dependencies = [ 307 | "semver", 308 | ] 309 | 310 | [[package]] 311 | name = "semver" 312 | version = "0.9.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 315 | dependencies = [ 316 | "semver-parser", 317 | ] 318 | 319 | [[package]] 320 | name = "semver-parser" 321 | version = "0.7.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 324 | 325 | [[package]] 326 | name = "syn" 327 | version = "1.0.109" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 330 | dependencies = [ 331 | "proc-macro2", 332 | "quote", 333 | "unicode-ident", 334 | ] 335 | 336 | [[package]] 337 | name = "typenum" 338 | version = "1.17.0" 339 | source = "registry+https://github.com/rust-lang/crates.io-index" 340 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 341 | 342 | [[package]] 343 | name = "unicode-ident" 344 | version = "1.0.12" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 347 | 348 | [[package]] 349 | name = "usb-device" 350 | version = "0.2.9" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" 353 | 354 | [[package]] 355 | name = "vcell" 356 | version = "0.1.3" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 359 | 360 | [[package]] 361 | name = "version_check" 362 | version = "0.9.4" 363 | source = "registry+https://github.com/rust-lang/crates.io-index" 364 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 365 | 366 | [[package]] 367 | name = "void" 368 | version = "1.0.2" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 371 | 372 | [[package]] 373 | name = "volatile-register" 374 | version = "0.2.2" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" 377 | dependencies = [ 378 | "vcell", 379 | ] 380 | -------------------------------------------------------------------------------- /boards/lpc55s69/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | #[cfg(not(any(feature = "semihosting",feature = "rtt")))] 5 | extern crate panic_halt; 6 | #[cfg(feature = "semihosting")] 7 | extern crate panic_semihosting; 8 | #[cfg(feature = "rtt")] 9 | use panic_probe as _; 10 | 11 | #[cfg(feature = "rtt")] 12 | use defmt_rtt as _; 13 | 14 | use core::cell::RefCell; 15 | 16 | use boot::{Image, MappedFlash}; 17 | use cortex_m_rt::entry; 18 | 19 | use embedded_hal::{digital::v2::OutputPin, timer::CountDown}; 20 | use hal::{drivers::{pins::Level, Timer, timer::Elapsed}, peripherals::ctimer::Ctimer, Enabled}; 21 | use lpc55_hal as hal; 22 | use embedded_time::rate::Extensions; 23 | use embedded_time::duration::Extensions as DurationExtensions; 24 | use embedded_time::duration::Microseconds; 25 | use embedded_time::fixed_point::FixedPoint; 26 | 27 | #[cfg(feature = "semihosting")] 28 | mod logging { 29 | pub use cortex_m_semihosting::{hprintln}; 30 | } 31 | 32 | mod flash; 33 | 34 | // Use 'info' if we are using defmt. 35 | #[cfg(feature = "rtt")] 36 | mod logging { 37 | macro_rules! hprintln { 38 | ($e:expr) => { 39 | defmt::error!($e); 40 | }; 41 | ($e:expr, $($args:expr),+) => { 42 | defmt::error!($e, $($args),+); 43 | }; 44 | } 45 | pub(crate) use hprintln; 46 | } 47 | 48 | // If semihosting is not available, just discard printed messages. It also 49 | // "uses" the arguments so disabling printing doesn't cause additional warnings. 50 | #[cfg(not(any(feature = "semihosting",feature = "rtt")))] 51 | mod logging { 52 | macro_rules! hprintln { 53 | ($_e:expr) => {{}}; 54 | ($_e:expr, $($x:expr),+) => { 55 | $(let _ = $x;);+ 56 | }; 57 | } 58 | pub(crate) use hprintln; 59 | } 60 | 61 | pub(crate) use logging::hprintln; 62 | 63 | #[entry] 64 | fn main() -> ! { 65 | let hal = hal::new(); 66 | 67 | hprintln!("---------- Start of code ----------"); 68 | 69 | let pins = hal::Pins::take().unwrap(); 70 | 71 | let mut syscon = hal.syscon; 72 | let mut gpio = hal.gpio.enabled(&mut syscon); 73 | let mut iocon = hal.iocon.enabled(&mut syscon); 74 | // let mut scb = hal.SCB; 75 | // let mut cpuid = hal.CPUID; 76 | 77 | /* 78 | scb.enable_icache(); 79 | scb.enable_dcache(&mut cpuid); 80 | 81 | let flash = hal.flash.release(); 82 | let bits = wait_done(&flash); 83 | hprintln!("wait_done status: {:x}", bits); 84 | hprintln!("Check 0 {:?}", read_check(&flash, 0)); 85 | hprintln!("Check 20000 {:?}", read_check(&flash, 0x20000)); 86 | hprintln!("Check 40000 {:?}", read_check(&flash, 0x40000)); 87 | */ 88 | 89 | /* 90 | let st = flash.int_status.read(); 91 | if st.done().bit_is_set() { 92 | hprintln!("Read done"); 93 | } else { 94 | hprintln!("Read not done"); 95 | } 96 | */ 97 | 98 | // Read the status register to make sure it works. 99 | 100 | // For now, trying to initialize the clocks again in the target locks up the 101 | // system. There is probably something that needs to be fixed in the hal. 102 | // For now, just run at our default slow clock. 103 | let mut anactrl = hal.anactrl; 104 | let mut pmc = hal.pmc; 105 | let clocks = hal::ClockRequirements::default() 106 | .system_frequency(100.MHz()) 107 | .configure(&mut anactrl, &mut pmc, &mut syscon) 108 | .unwrap(); 109 | let _ = clocks; 110 | 111 | // Try using the timer to determine how long some of these things take. 112 | let ctimer = hal 113 | .ctimer 114 | .1 115 | .enabled(&mut syscon, clocks.support_1mhz_fro_token().unwrap()); 116 | let mut cdriver = Timer::new(ctimer); 117 | 118 | /* 119 | for addr in [0, 0x20000, 0x40000] { 120 | let (ok, elapsed) = measure(&mut cdriver, || { 121 | (0..1000).map(|_| read_check(&flash, addr)).last().unwrap() 122 | }); 123 | hprintln!("Check 0x{:x} {:?} {}us", addr, ok, elapsed); 124 | } 125 | 126 | // There is an image there, read it to get it into the cache. 127 | hprintln!("@20000->{:>8x}", 128 | unsafe { 129 | *(0x20000 as *const u32) 130 | }); 131 | 132 | // Erase at 0x20000. 133 | let (ok, elapsed) = measure(&mut cdriver, || erase(&flash, 0x20000, 512)); 134 | hprintln!("Erase 0x20000 {:?} {}us", ok, elapsed); 135 | 136 | // Recheck. 137 | let (ok, elapsed) = measure(&mut cdriver, || read_check(&flash, 0x20000)); 138 | hprintln!("Read check 0x20000 {:?} {}us", ok, elapsed); 139 | 140 | // Program a test pattern. 141 | let mut pattern = [0u8; 512]; 142 | for i in 0..512 { 143 | pattern[i] = (i & 0xff) as u8; 144 | } 145 | let (ok, elapsed) = measure(&mut cdriver, || program_page(&flash, 0x20000, &pattern)); 146 | hprintln!("Program 0x20000 {:?} {}us", ok, elapsed); 147 | 148 | // Invalidate the caches. 149 | /* 150 | scb.invalidate_icache(); 151 | unsafe { 152 | scb.invalidate_dcache_by_address(0x20000, 512); 153 | } 154 | */ 155 | 156 | // Print out some, to see. 157 | for i in 0..32 { 158 | hprintln!("{:>08x}", 159 | unsafe { 160 | *((0x20000 + i * 4) as *const u32) 161 | } 162 | ); 163 | } 164 | 165 | /* 166 | cdriver.start(1_000_000.microseconds()); 167 | let vvv = read_check(&flash, 0); 168 | let now = cdriver.elapsed(); 169 | // hprintln!("Check 0 {:?}", read_check(&flash, 0)); 170 | hprintln!("Check 0 {:?} {}", vvv, now); 171 | hprintln!("Check 20000 {:?}", read_check(&flash, 0x20000)); 172 | hprintln!("Check 40000 {:?}", read_check(&flash, 0x40000)); 173 | */ 174 | */ 175 | 176 | let mut red = pins 177 | .pio1_6 178 | .into_gpio_pin(&mut iocon, &mut gpio) 179 | .into_output(Level::High); 180 | 181 | let flash = hal.flash.release(); 182 | let flash = flash::LpcFlash::new(flash); 183 | let slot0 = flash.partition(0x20000, 0x20000).unwrap(); 184 | 185 | let slot0 = RefCell::new(slot0); 186 | 187 | let image = Image::from_flash(&slot0).unwrap(); 188 | let ((), elapsed) = measure(&mut cdriver, || image.validate().unwrap()); 189 | hprintln!("validate: {}us", elapsed.integer()); 190 | chain(&image).unwrap(); 191 | 192 | loop { 193 | red.set_low().unwrap(); 194 | hal::wait_at_least(300_000); 195 | red.set_high().unwrap(); 196 | hal::wait_at_least(300_000); 197 | } 198 | } 199 | 200 | fn measure, F: FnOnce() -> T>(timer: &mut Timer, action: F) -> (T, Microseconds) { 201 | timer.start(1_000_000.microseconds()); 202 | let before = timer.elapsed(); 203 | let result = action(); 204 | let after = timer.elapsed(); 205 | (result, after - before) 206 | } 207 | 208 | /* 209 | // Try putting some code into RAM, and see if we can execute it there. In this 210 | // case, we want to try accessing hardware. 211 | #[inline(never)] 212 | #[link_section = ".data.flash"] 213 | fn wait_done(flash: &FLASH) -> u32 { 214 | while flash.int_status.read().done().bit_is_clear() { 215 | } 216 | let bits = flash.int_status.read().bits(); 217 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 218 | bits 219 | } 220 | */ 221 | 222 | /* 223 | /// Determine if a page has been programmed. If this returns true, it is likely 224 | /// that reads from that page will not result in bus faults. 225 | #[inline(never)] 226 | //#[link_section = ".data.flash"] 227 | fn read_check(flash: &FLASH, addr: u32) -> bool { 228 | // Wait for anything to complete, and clear status. 229 | /* 230 | while flash.int_status.read().done().bit_is_clear() { 231 | } 232 | */ 233 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 234 | 235 | flash.starta.write(|w| unsafe{w.bits(addr >> 4)}); 236 | flash.stopa.write(|w| unsafe{w.bits(addr >> 4)}); 237 | flash.cmd.write(|w| unsafe{w.bits(6)}); 238 | while flash.int_status.read().done().bit_is_clear() { 239 | } 240 | 241 | let good = flash.int_status.read().fail().bit_is_clear(); 242 | 243 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 244 | 245 | good 246 | } 247 | */ 248 | 249 | /* 250 | /// Erase a range. 251 | fn erase(flash: &FLASH, base: u32, length: u32) -> bool { 252 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 253 | if length % 512 != 0 { 254 | return false; 255 | } 256 | let ending = base + length - 511; 257 | flash.starta.write(|w| unsafe{w.bits(base >> 4)}); 258 | flash.stopa.write(|w| unsafe{w.bits(ending >> 4)}); 259 | flash.cmd.write(|w| unsafe{w.bits(4)}); 260 | while flash.int_status.read().done().bit_is_clear() { 261 | } 262 | 263 | let good = flash.int_status.read().fail().bit_is_clear(); 264 | 265 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 266 | 267 | good 268 | } 269 | */ 270 | 271 | /* 272 | /// Program a single page. 273 | fn program_page(flash: &FLASH, base: u32, page: &[u8]) -> bool { 274 | flash.int_clr_status.write(|w| w.done().set_bit().err().set_bit().fail().set_bit().ecc_err().set_bit()); 275 | if page.len() != 512 { 276 | return false; 277 | } 278 | for word in 0..32 { 279 | flash.starta.write(|w| unsafe{w.bits(word)}); 280 | for column in 0..4 { 281 | let base = ((word << 4) + (column << 2)) as usize; 282 | let cell = LittleEndian::read_u32(&page[base..base+4]); 283 | flash.dataw[column as usize].write(|w| unsafe{w.bits(cell)}); 284 | } 285 | flash.cmd.write(|w| unsafe{w.bits(8)}); 286 | while flash.int_status.read().done().bit_is_clear() { 287 | } 288 | let good = flash.int_status.read().fail().bit_is_clear(); 289 | if !good { 290 | return false; 291 | } 292 | } 293 | 294 | flash.starta.write(|w| unsafe{w.bits(base >> 4)}); 295 | flash.cmd.write(|w| unsafe{w.bits(12)}); 296 | while flash.int_status.read().done().bit_is_clear() { 297 | } 298 | let good = flash.int_status.read().fail().bit_is_clear(); 299 | good 300 | } 301 | */ 302 | 303 | // For debugging. 304 | // TODO: Handle the storage error, converting to a better error. 305 | #[inline(never)] 306 | pub fn chain<'f, F: MappedFlash>(image: &Image<'f, F>) -> Result<(), flash::Error> { 307 | // Chain the next image, assuming the image has been validated. 308 | 309 | let reset_base = image.get_image_base(); 310 | // let reset = unsafe {&*(reset_base as *const ResetVector)}; 311 | // hprintln!("chain {}", reset); 312 | unsafe { 313 | #[allow(unused_mut)] 314 | let mut p = cortex_m::Peripherals::steal(); 315 | p.SCB.vtor.write(reset_base as u32); 316 | 317 | cortex_m::asm::bootload(reset_base as *const u32); 318 | } 319 | 320 | // Ok(()) 321 | } 322 | 323 | // TODO: We don't really want to just read this directly, as it will fault if no 324 | // image was written here. But, read without faulting is still WIP. 325 | 326 | /// The Cortex-M reset vector, sits at the start of the vector table. 327 | #[derive(Debug)] 328 | #[repr(C)] 329 | struct ResetVector { 330 | msp: u32, 331 | reset: u32, 332 | } 333 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /boot/src/image.rs: -------------------------------------------------------------------------------- 1 | //! Boot image support 2 | 3 | use core::{cell::RefCell, mem::size_of}; 4 | 5 | use asraw::{AsMutRaw, AsRaw}; 6 | use storage::ReadFlash; 7 | use sha2::{Digest, Sha256}; 8 | 9 | use crate::{MappedFlash, Error, Result}; 10 | 11 | /// To make development a little easier, allow println in the 'std' code, and 12 | /// just make it vanish when we are no_std. 13 | #[cfg(not(feature = "std"))] 14 | macro_rules! println { 15 | ($($_e:expr),+) => { {} }; 16 | } 17 | 18 | /// The image header contains the following magic value, indicating the 19 | /// interpretation of the rest of the image header. 20 | pub const IMAGE_MAGIC: u32 = 0x96f3b83d; 21 | 22 | /// The result of a SHA256 hash, appropriate for stack allocation. 23 | type Hash256 = [u8; 32]; 24 | 25 | /// An image is a bootable image residing in a flash partition. There is a 26 | /// header at the beginning, and metadata immediately following the image. 27 | /// This holds on to a RefCell to the flash to bind the data to a particular flash. 28 | pub struct Image<'f, F> { 29 | flash: &'f RefCell, 30 | #[allow(dead_code)] 31 | pub header: ImageHeader, 32 | tlv_base: usize, 33 | tlv_size: usize, 34 | } 35 | 36 | impl<'f, F: ReadFlash> Image<'f, F> { 37 | /// Make an image from flash, if the image has a valid header. This does not 38 | /// indicate that the image itself is valid, merely that the header 39 | /// indicates an image is present. 40 | pub fn from_flash(flash: &'f RefCell) -> Result> { 41 | let mut header = ImageHeader::default(); 42 | flash.borrow_mut().read(0, header.as_mut_raw())?; 43 | 44 | if header.magic != IMAGE_MAGIC { 45 | return Err(Error::InvalidImage); 46 | } 47 | 48 | // Find the base address of the TLV. 49 | let tlv_base = (header.img_size as usize) 50 | .checked_add(header.hdr_size as usize) 51 | .ok_or(Error::InvalidImage)?; 52 | 53 | // Overflow of the partition will be checked by the flash device. 54 | // Capacity is not guaranteed to be returned. 55 | 56 | // Simple case of just a single TLV entry for hash. TODO: More 57 | // sophisticated handling should be done separate from here. 58 | let mut info = TlvInfo::default(); 59 | flash 60 | .borrow_mut() 61 | .read(tlv_base, info.as_mut_raw())?; 62 | 63 | // println!("header: {:#x?}", header); 64 | // println!("tlv: {:#x?}", info); 65 | 66 | if info.magic != TLV_INFO_MAGIC { 67 | return Err(Error::InvalidImage); 68 | } 69 | // TODO: If we support the protected TLV, the size computation will have 70 | // to change. 71 | let tlv_size = info.len as usize; 72 | 73 | // TODO: This can be done just with validate. 74 | let mut pos = size_of::(); 75 | while pos < info.len as usize { 76 | let mut entry = TlvEntry::default(); 77 | flash 78 | .borrow_mut() 79 | .read(tlv_base + pos, entry.as_mut_raw())?; 80 | // println!("entry: {:x?}", entry); 81 | 82 | pos += size_of::() + entry.len as usize; 83 | } 84 | 85 | Ok(Image { 86 | flash, 87 | header, 88 | tlv_base, 89 | tlv_size, 90 | }) 91 | } 92 | 93 | /// Iterate over the elements of the Tlv. 94 | pub fn tlvs<'a>(&'a self) -> Result> { 95 | // Check the header. 96 | let mut info = TlvInfo::default(); 97 | self.flash 98 | .borrow_mut() 99 | .read(self.tlv_base, info.as_mut_raw())?; 100 | 101 | if info.magic != TLV_INFO_MAGIC { 102 | return Err(Error::InvalidImage); 103 | } 104 | 105 | Ok(TlvIter { 106 | image: self, 107 | pos: size_of::(), 108 | limit: info.len as usize, 109 | }) 110 | } 111 | 112 | /// Validate this image. Check the TLV entries, making sure that they are 113 | /// sufficient, and that indicated items, such as hashes and signatures are 114 | /// valid. 115 | pub fn validate(&self) -> Result<()> { 116 | // Things we must see. 117 | let mut seen_sha = false; 118 | 119 | for elt in self.tlvs()? { 120 | let elt = elt?; 121 | // println!("TLV: 0x{:x}", elt.kind()); 122 | match elt.kind() { 123 | TLV_SHA256 => { 124 | if seen_sha { 125 | // Only a single hash is allowed. 126 | return Err(Error::InvalidImage); 127 | } 128 | seen_sha = true; 129 | let mut hash = [0u8; 32]; 130 | elt.read_data(&mut hash)?; 131 | let image_hash = self.calculate_sha256()?; 132 | if hash != image_hash { 133 | println!("Hash verification failure"); 134 | return Err(Error::InvalidImage); 135 | } 136 | } 137 | kind => { 138 | // Allow to be unused for embedded. 139 | let _ = kind; 140 | println!("Unexpected TLV 0x{:x}", kind); 141 | return Err(Error::InvalidImage); 142 | } 143 | } 144 | } 145 | if !seen_sha { 146 | println!("Expecting SHA TLV"); 147 | return Err(Error::InvalidImage); 148 | } 149 | Ok(()) 150 | } 151 | 152 | /// Compute the hash of the data portion of the image. 153 | fn calculate_sha256(&self) -> Result { 154 | let mut hasher = Sha256::new(); 155 | let mut buffer = [0u8; 128]; 156 | let mut pos = 0; 157 | while pos < self.tlv_base { 158 | let todo = (self.tlv_base - pos).min(buffer.len()); 159 | let buf = &mut buffer[0..todo]; 160 | self.flash.borrow_mut().read(pos, buf)?; 161 | hasher.update(buf); 162 | pos += todo; 163 | } 164 | let mut result = [0u8; 32]; 165 | result.copy_from_slice(hasher.finalize().as_slice()); 166 | Ok(result) 167 | } 168 | } 169 | 170 | impl<'a, F> Image<'a, F> { 171 | /// Return the size, in bytes, of the entire image, including the TLV. 172 | pub fn full_image_size(&self) -> usize { 173 | self.tlv_base + self.tlv_size 174 | } 175 | } 176 | 177 | pub struct TlvIter<'a, 'f, F> { 178 | image: &'a Image<'f, F>, 179 | pos: usize, 180 | limit: usize, 181 | } 182 | 183 | pub struct TlvIterEntry<'f, F> { 184 | flash: &'f RefCell, 185 | kind: u16, 186 | pos: usize, 187 | len: usize, 188 | } 189 | 190 | /// Helper like '?' for iterator operations, where errors should return 191 | /// Some(Err(e)) instead of just the error. This macro contains a return. 192 | macro_rules! iter_try { 193 | ($e:expr) => { 194 | match $e { 195 | Ok(r) => r, 196 | Err(e) => return Some(Err(e.into())), 197 | } 198 | }; 199 | } 200 | 201 | impl<'a, 'f, F: ReadFlash> Iterator for TlvIter<'a, 'f, F> { 202 | type Item = Result>; 203 | fn next(&mut self) -> Option { 204 | if self.pos >= self.limit { 205 | return None; 206 | } 207 | 208 | let mut entry = TlvEntry::default(); 209 | let pos = iter_try!(self 210 | .image 211 | .tlv_base 212 | .checked_add(self.pos) 213 | .ok_or(Error::InvalidImage)); 214 | iter_try!(self 215 | .image 216 | .flash 217 | .borrow_mut() 218 | .read(pos, entry.as_mut_raw())); 219 | let data_pos = iter_try!(pos 220 | .checked_add(size_of::()) 221 | .ok_or(Error::InvalidImage)); 222 | self.pos = iter_try!(data_pos 223 | .checked_add(entry.len as usize) 224 | .ok_or(Error::InvalidImage)); 225 | Some(Ok(TlvIterEntry { 226 | flash: self.image.flash, 227 | kind: entry.kind, 228 | pos: data_pos, 229 | len: entry.len as usize, 230 | })) 231 | } 232 | } 233 | 234 | impl<'f, F: ReadFlash> TlvIterEntry<'f, F> { 235 | /// What is the kind of this TLV entry. 236 | pub fn kind(&self) -> u16 { 237 | self.kind 238 | } 239 | 240 | /// What is the size of the payload. 241 | pub fn data_len(&self) -> usize { 242 | self.len 243 | } 244 | 245 | /// Read the payload into the given bytes. 246 | pub fn read_data(&self, data: &mut [u8]) -> Result<()> { 247 | if data.len() != self.len { 248 | // TODO: Is something more meaningful here? 249 | return Err(Error::InvalidImage); 250 | } 251 | self.flash.borrow_mut().read(self.pos, data)?; 252 | Ok(()) 253 | } 254 | } 255 | 256 | /// For mapped flash, we can get the base address of the XIP area. 257 | impl<'f, F: MappedFlash> Image<'f, F> { 258 | pub fn get_image_base(&self) -> usize { 259 | self.flash.borrow().get_base() + self.header.hdr_size as usize 260 | } 261 | } 262 | 263 | /// The image begins with the following header. This is intended to be 264 | /// interpreted as a C struct. 265 | #[derive(Debug, Default)] 266 | #[repr(C)] 267 | pub struct ImageHeader { 268 | /// Magic number, indicates this particular header. 269 | magic: u32, 270 | /// The address to load this image. Only used for non-XIP. It seems to be 271 | /// used if non-zero, which assumes that RAM does not start at address zero. 272 | load_addr: u32, 273 | /// The size of the header. This struct is at the beginning, and there is 274 | /// some amount of padding before the actual image starts. This is used 275 | /// because many architectures place alignment requirements on the runable 276 | /// image. 277 | hdr_size: u16, 278 | /// The size of the protected TLV. The size is included here. See below on 279 | /// the TLV for the meaning of this value. 280 | protected_tlv_size: u16, 281 | /// The size of the image, not counting the header. 282 | img_size: u32, 283 | /// Flags for this image. These indicate aspects, but are largely unused. 284 | flags: u32, 285 | /// Version of this particular image. 286 | version: ImageVersion, 287 | /// Padding, to reach a nicely aligned minimum size. 288 | pad1: u32, 289 | } 290 | 291 | impl AsRaw for ImageHeader {} 292 | unsafe impl AsMutRaw for ImageHeader {} 293 | 294 | /// Each image has a version. This is a pseudo-semantic version used to 295 | /// determine upgrade elligibility and compatible between multi-image setups. 296 | #[derive(Debug, Default)] 297 | #[repr(C)] 298 | struct ImageVersion { 299 | major: u8, 300 | minor: u8, 301 | revision: u16, 302 | build_num: u32, 303 | } 304 | 305 | /// The TLV block contains this header. 306 | #[derive(Debug, Default)] 307 | #[repr(C)] 308 | struct TlvInfo { 309 | /// Magic one of TLV_INFO_MAGIC or TLV_PROT_INFO_MAGIC. 310 | magic: u16, 311 | /// Length of TLV, including this header. 312 | len: u16, 313 | } 314 | 315 | const TLV_INFO_MAGIC: u16 = 0x6907; 316 | 317 | // Supported TLVS 318 | const TLV_SHA256: u16 = 0x10; 319 | 320 | impl AsRaw for TlvInfo {} 321 | unsafe impl AsMutRaw for TlvInfo {} 322 | 323 | /// Each TLV entry is preceeded by this header. 324 | #[derive(Debug, Default)] 325 | #[repr(C)] 326 | struct TlvEntry { 327 | /// Magic one of TLV_INFO_MAGIC or TLV_PROT_INFO_MAGIC. 328 | kind: u16, 329 | /// Length of TLV, including this header. 330 | len: u16, 331 | } 332 | 333 | impl AsRaw for TlvEntry {} 334 | unsafe impl AsMutRaw for TlvEntry {} 335 | -------------------------------------------------------------------------------- /boot/src/status.rs: -------------------------------------------------------------------------------- 1 | //! Image upgrade status 2 | //! 3 | //! The image upgrade keeps track of its progress through a set of 'status' data 4 | //! that is represented at the end of one or more of the partitions of the 5 | //! flash. The characterists of the flash determine which of two fairly 6 | //! different techniques we will use to store this data. 7 | //! 8 | //! The status represents one a small number of states that we can be in: 9 | //! 10 | //! - None. The images are just present, and we aren't expecting to do an 11 | //! upgrade. 12 | //! - Request. A new image is in the upgrade slot, and we've marked for 13 | //! an upgrade. 14 | //! - Started. Status data is calculated and recorded. What data depends on the 15 | //! upgrade method. 16 | //! - Move done. The move stage of an upgrade has completed. 17 | //! - Copy done. The swap itself is finished. 18 | //! - Image ok. The image is valid, and a revert will not be attempted. 19 | //! 20 | //! None does not have status data associated with it. 21 | //! Request has status data associated with the upgrade slot 22 | //! The remaining status data is always stored in the destination slot. 23 | //! 24 | //! Depending on the request, copy done and image ok might be set together. 25 | //! 26 | //! The image goes through the following steps. 27 | //! 28 | //! (m = meta, md = move done, cd = copy done, ok = image ok) 29 | //! 30 | //! +------------------+------------------+--------------------------------+ 31 | //! | Slot 0 status | Slot 1 status | State 32 | //! +------------------+------------------+--------------------------------+ 33 | //! | blank | blank | None 34 | //! | any | magic | Request 35 | //! | magic+m | magic | Started 36 | //! | magic+m+md | magic | Move Done 37 | //! | magic+m+md+cd | magic | Copy Done 38 | //! | magic+m+md+cd+ok | magic | Image ok - no further changes. 39 | //! | magic+m+md+cd | magic+m | Started revert 40 | //! | magic+m+md+cd | magic+m+md | Move Done revert 41 | //! | magic+m+md+cd+ok | magic+m+md+cd+ok | Copy Done revert - no changes 42 | //! | magic+m+md+cd+ok | magic+m+md+cd+ok | Copy Done revert - no changes 43 | //! +------------------+------------------+--------------------------------+ 44 | //! 45 | //! The characteristics of the flash device itself indicate whether we are in 46 | //! "paged" status mode, or in "overwrite" status mode. 47 | //! 48 | //! Paged mode views the flash as follows (high address at the top, each section 49 | //! is one sector). 50 | //! +-----+--------------------------+ 51 | //! | n-1 | magic 52 | //! | | age + flags 53 | //! | | status-hash 54 | //! | | hash-seed 55 | //! | | image-A size in bytes 56 | //! | | image-B size in bytes 57 | //! | | encryption state 58 | //! | | first k sector hashes 59 | //! +-----+--------------------------+ 60 | //! | n-2 | magic 61 | //! | | age + flags 62 | //! | | status-hash 63 | //! | | hash-seed 64 | //! | | first k sector hashes 65 | //! +-----+--------------------------+ 66 | //! | n-3 | next page-size/4 hashes 67 | //! +-----+--------------------------+ 68 | //! | n-4 | next page-size/4 hashes 69 | //! +-----+--------------------------+ 70 | //! | | etc 71 | //! +-----+--------------------------+ 72 | //! 73 | //! Overwrite mode is instead, as follows. It makes the assumption that the 74 | //! write size is smaller, and blocks for the flags can be left unwritten. 75 | //! There is a single sector at the end of flash containing the information. 76 | //! +-----+--------------------------------+ 77 | //! | n-1 | magic 78 | //! | | overwrite marker + alignment 79 | //! | | status hash (skips the flags as those can change.) 80 | //! | | hash-seed 81 | //! | | image-A size in bytes 82 | //! | | image-B size in bytes 83 | //! | | encryption state 84 | //! | | .. pad to write boundary .. 85 | //! | | flag - move done 86 | //! | | .. pad to write boundary .. 87 | //! | | flag - copy done 88 | //! | | .. pad to write boundary .. 89 | //! | | flag - image ok 90 | //! | | .. pad to write boundary .. 91 | //! | | first k sector hashes 92 | //! +-----+--------------------------------+ 93 | //! | n-2 | next sector-size/4 hashes 94 | //! +-----+--------------------------------+ 95 | //! | n-3 | next sector-size/4 hashes 96 | //! | | .. pad to write boundary .. 97 | //! | | end of image payload 98 | //! +-----+--------------------------------+ 99 | //! (if not clear, the flags each _start_ at a write boundary) 100 | //! 101 | //! Because of partial writes within a sector, overwrite mode allows the end of 102 | //! the image to share the last sector with the status data. The number of 103 | //! sectors involved will depend on the sizes of the images. 104 | 105 | // use storage::ReadFlash; 106 | 107 | use core::mem::size_of; 108 | 109 | use crate::Result; 110 | use asraw::{AsRaw, AsMutRaw}; 111 | use storage::Flash; 112 | 113 | mod sizes { 114 | /// Maximum expected image size. 115 | const MAX_IMAGE: usize = 1024 * 1024; 116 | 117 | /// Smallest page size for paged mode. 118 | const SMALLEST_PAGED_SECTOR: usize = 512; 119 | 120 | /// Smallest sector in overwrite mode. 121 | const SMALLEST_SECTOR: usize = 4096; 122 | 123 | /// Number of hashes expected in paged. 124 | const PAGED_HASHES: usize = MAX_IMAGE.div_ceil(SMALLEST_PAGED_SECTOR); 125 | 126 | /// Number of hashes expected in overwrite. 127 | const OVERWRITE_HASHES: usize = MAX_IMAGE.div_ceil(SMALLEST_SECTOR); 128 | 129 | /// Max needed hashes. Will need to store twice this in status are. 130 | #[allow(dead_code)] 131 | pub const MAX_HASHES: usize = { 132 | if PAGED_HASHES > OVERWRITE_HASHES { 133 | PAGED_HASHES 134 | } else { 135 | OVERWRITE_HASHES 136 | } 137 | }; 138 | // PAGED_HASHES.max(OVERWRITE_HASHES); 139 | 140 | /// How many sectors of hash can we expect in paged. 141 | pub const MAX_PAGED_HASH_SECTORS: usize = 142 | (PAGED_HASHES + PAGED_HASHES).div_ceil(SMALLEST_PAGED_SECTOR); 143 | pub const MAX_OVERWRITE_HASH_SECTORS: usize = 144 | (OVERWRITE_HASHES + OVERWRITE_HASHES).div_ceil(SMALLEST_SECTOR); 145 | 146 | pub const MAX_HASH_SECTORS: usize = { 147 | if MAX_PAGED_HASH_SECTORS > MAX_OVERWRITE_HASH_SECTORS { 148 | MAX_PAGED_HASH_SECTORS 149 | } else { 150 | MAX_OVERWRITE_HASH_SECTORS 151 | } 152 | }; 153 | 154 | pub type HashVec = heapless::Vec; 155 | // pub type PHashVec = heapless::Vec; 156 | // pub type OHashVec = heapless::Vec; 157 | } 158 | 159 | /// Information needed to calculate status layout. 160 | #[derive(Debug)] 161 | pub struct SlotInfo { 162 | /// Device write size. 163 | pub write_size: usize, 164 | /// Device erase size. 165 | pub erase_size: usize, 166 | /// Size of full flash slot. 167 | pub capacity: usize, 168 | /// Size, in bytes, of the image, including trailing TLV, etc. 169 | pub image_size: usize, 170 | } 171 | 172 | impl SlotInfo { 173 | /// Build SlotInfo out of an image and a flash device. 174 | pub fn from_data(image_size: usize, flash: &F) -> SlotInfo { 175 | let write_size = flash.write_size(); 176 | let erase_size = flash.erase_size(); 177 | let capacity = flash.capacity(); 178 | SlotInfo { write_size, erase_size, capacity, image_size } 179 | } 180 | 181 | /// Determine the status style for this slot. 182 | pub fn status_style(&self) -> StatusStyle { 183 | if self.write_size <= 32 { 184 | return StatusStyle::OverWrite; 185 | } 186 | 187 | if self.erase_size <= 4096 { 188 | return StatusStyle::Paged; 189 | } 190 | 191 | // It is unclear how to support this flash. 192 | panic!("Device configuration unsupported"); 193 | } 194 | 195 | /// Given our info, compute the status layout for this particular slot. The 196 | /// other slot information is needed to calculate this. 197 | pub fn status_layout(&self, upgrade: &SlotInfo) -> Result { 198 | // Use the larger of the two erase sizes for the swap. 199 | let erase_size = self.erase_size.max(upgrade.erase_size); 200 | 201 | assert!(self.erase_size.is_power_of_two()); 202 | assert!(self.write_size.is_power_of_two()); 203 | 204 | let image_sectors = [ 205 | self.image_size.div_ceil(erase_size), 206 | upgrade.image_size.div_ceil(erase_size) 207 | ]; 208 | let style = self.status_style(); 209 | // println!("Erase size: {}", erase_size); 210 | // println!("Image sectors: {:?}", image_sectors); 211 | // println!("Tail size: {}", size_of::()); 212 | // println!("Style: {:?}", style); 213 | 214 | // Calculate the layout of our last page, or two, depending on mode. 215 | let mut pos = erase_size; 216 | 217 | // The tail goes at the end. 218 | pos -= size_of::(); 219 | let tail_pos = pos; 220 | 221 | // The status flags are present 222 | let flags = if style == StatusStyle::OverWrite { 223 | // Round down to be write aligned. 224 | pos = pos & !(self.write_size - 1); 225 | 226 | pos -= self.write_size; 227 | let move_done_flag = pos; 228 | 229 | pos -= self.write_size; 230 | let copy_done_flag = pos; 231 | 232 | pos -= self.write_size; 233 | let image_ok_flag = pos; 234 | 235 | Some([move_done_flag, copy_done_flag, image_ok_flag]) 236 | } else { 237 | None 238 | }; 239 | 240 | let end_hashes = pos; 241 | pos &= !(erase_size - 1); 242 | 243 | let total_image_sectors = image_sectors[0] + image_sectors[1]; 244 | let inline_hashes = ((end_hashes - pos) / 4).min(total_image_sectors); 245 | 246 | // Calculate additional pages of hashes. 247 | let mut hash_pages = sizes::HashVec::new(); 248 | let mut count = total_image_sectors - inline_hashes; 249 | while count > 0 { 250 | let n = (erase_size / 4).min(count); 251 | hash_pages.push(n).unwrap(); 252 | count -= n; 253 | } 254 | 255 | // println!("Hashes: {} bytes", end_hashes - pos); 256 | // println!("Tail pos: {}", tail_pos); 257 | // println!("flags pos: {:?}", flags); 258 | // println!("inline hashes: {}", inline_hashes); 259 | // println!("Additional hashes: {:?}", hash_pages); 260 | 261 | Ok(StatusLayout { 262 | style, 263 | erase_size, 264 | write_size: self.write_size, 265 | image_sectors, 266 | tail_pos, 267 | flags, 268 | inline_hashes, 269 | hash_pages, 270 | }) 271 | } 272 | } 273 | 274 | #[derive(Debug, Eq, PartialEq)] 275 | pub enum StatusStyle { 276 | Paged, 277 | OverWrite 278 | } 279 | 280 | #[derive(Debug)] 281 | pub struct StatusLayout { 282 | pub style: StatusStyle, 283 | pub erase_size: usize, 284 | pub write_size: usize, 285 | pub image_sectors: [usize; 2], 286 | pub tail_pos: usize, 287 | pub flags: Option<[usize; 3]>, 288 | pub inline_hashes: usize, 289 | pub hash_pages: sizes::HashVec, 290 | } 291 | 292 | impl StatusLayout { 293 | pub fn read(&self, flash: &mut F) -> Result<()> { 294 | // Calculate the address of the last page. 295 | let last_page = ((flash.capacity() / flash.erase_size()) - 1) * flash.erase_size(); 296 | 297 | println!("Last page: {:x}", last_page); 298 | let last_tail_pos = last_page + self.tail_pos; 299 | 300 | let mut last_tail = StatusTail::default(); 301 | flash.read(last_tail_pos, last_tail.as_mut_raw())?; 302 | 303 | Ok(()) 304 | } 305 | } 306 | 307 | /// The status tail. This data is placed at the very end of the slot. 308 | #[derive(Debug, Default)] 309 | #[repr(C)] 310 | struct StatusTail { 311 | /// The encryption key, used if we are encrypting in/out of slot0. 312 | enc_key: [u8; 16], 313 | /// Size of the main image, in bytes, includes TLV. 314 | main_size: u32, 315 | /// Size of the upgrade image, in bytes, includes TLV. 316 | upgrade_size: u32, 317 | /// The hash seed. Added to the beginning of the hash to make it unique. 318 | hash_seed: u32, 319 | /// Log2 of the write_size in this slot. (1 << write_log) gives the write size. 320 | write_log: u8, 321 | /// Log2 of the erase size. This is the larest of the two slots. 322 | erase_log: u8, 323 | /// Flags to indicate status. Flags are here, unless the 'age' field is set 324 | /// to 0xff, which indicates that we are in overwrite not paged mode, and 325 | /// the flags are before this data. 326 | flags: u8, 327 | /// Age of this page, or 0xff to indicate overwrite mode. 328 | age: u8, 329 | /// The magic number. This should land at the end of the image. 330 | magic: [u8; 16], 331 | } 332 | 333 | impl AsRaw for StatusTail {} 334 | unsafe impl AsMutRaw for StatusTail {} 335 | 336 | /* 337 | #[repr(u8)] 338 | pub enum Flags { 339 | MoveDone = 0b0001, 340 | CopyDone = 0b0010, 341 | ImageOk = 0b0100, 342 | } 343 | */ 344 | -------------------------------------------------------------------------------- /boards/stm32h745/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "bare-metal" 7 | version = "0.2.5" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 10 | dependencies = [ 11 | "rustc_version", 12 | ] 13 | 14 | [[package]] 15 | name = "bare-metal" 16 | version = "1.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" 19 | 20 | [[package]] 21 | name = "bitfield" 22 | version = "0.13.2" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 25 | 26 | [[package]] 27 | name = "bitflags" 28 | version = "1.3.2" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 31 | 32 | [[package]] 33 | name = "cast" 34 | version = "0.3.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" 37 | 38 | [[package]] 39 | name = "cortex-m" 40 | version = "0.7.7" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" 43 | dependencies = [ 44 | "bare-metal 0.2.5", 45 | "bitfield", 46 | "critical-section", 47 | "embedded-hal", 48 | "volatile-register", 49 | ] 50 | 51 | [[package]] 52 | name = "cortex-m-rt" 53 | version = "0.7.3" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" 56 | dependencies = [ 57 | "cortex-m-rt-macros", 58 | ] 59 | 60 | [[package]] 61 | name = "cortex-m-rt-macros" 62 | version = "0.7.0" 63 | source = "registry+https://github.com/rust-lang/crates.io-index" 64 | checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" 65 | dependencies = [ 66 | "proc-macro2", 67 | "quote", 68 | "syn 1.0.109", 69 | ] 70 | 71 | [[package]] 72 | name = "cortex-m-semihosting" 73 | version = "0.5.0" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" 76 | dependencies = [ 77 | "cortex-m", 78 | ] 79 | 80 | [[package]] 81 | name = "critical-section" 82 | version = "1.1.2" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 85 | 86 | [[package]] 87 | name = "defmt" 88 | version = "0.3.5" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" 91 | dependencies = [ 92 | "bitflags", 93 | "defmt-macros", 94 | ] 95 | 96 | [[package]] 97 | name = "defmt-macros" 98 | version = "0.3.6" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" 101 | dependencies = [ 102 | "defmt-parser", 103 | "proc-macro-error", 104 | "proc-macro2", 105 | "quote", 106 | "syn 2.0.39", 107 | ] 108 | 109 | [[package]] 110 | name = "defmt-parser" 111 | version = "0.3.3" 112 | source = "registry+https://github.com/rust-lang/crates.io-index" 113 | checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" 114 | dependencies = [ 115 | "thiserror", 116 | ] 117 | 118 | [[package]] 119 | name = "defmt-rtt" 120 | version = "0.4.0" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "609923761264dd99ed9c7d209718cda4631c5fe84668e0f0960124cbb844c49f" 123 | dependencies = [ 124 | "critical-section", 125 | "defmt", 126 | ] 127 | 128 | [[package]] 129 | name = "embedded-dma" 130 | version = "0.2.0" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" 133 | dependencies = [ 134 | "stable_deref_trait", 135 | ] 136 | 137 | [[package]] 138 | name = "embedded-hal" 139 | version = "0.2.7" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 142 | dependencies = [ 143 | "nb 0.1.3", 144 | "void", 145 | ] 146 | 147 | [[package]] 148 | name = "embedded-storage" 149 | version = "0.3.0" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "156d7a2fdd98ebbf9ae579cbceca3058cff946e13f8e17b90e3511db0508c723" 152 | 153 | [[package]] 154 | name = "fugit" 155 | version = "0.3.7" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" 158 | dependencies = [ 159 | "gcd", 160 | ] 161 | 162 | [[package]] 163 | name = "gcd" 164 | version = "2.3.0" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" 167 | 168 | [[package]] 169 | name = "nb" 170 | version = "0.1.3" 171 | source = "registry+https://github.com/rust-lang/crates.io-index" 172 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 173 | dependencies = [ 174 | "nb 1.1.0", 175 | ] 176 | 177 | [[package]] 178 | name = "nb" 179 | version = "1.1.0" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 182 | 183 | [[package]] 184 | name = "panic-halt" 185 | version = "0.2.0" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" 188 | 189 | [[package]] 190 | name = "panic-itm" 191 | version = "0.4.2" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "3d577d97d1b31268087b6dddf2470e6794ef5eee87d9dca7fcd0481695391a4c" 194 | dependencies = [ 195 | "cortex-m", 196 | ] 197 | 198 | [[package]] 199 | name = "panic-probe" 200 | version = "0.3.1" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9" 203 | dependencies = [ 204 | "cortex-m", 205 | "defmt", 206 | ] 207 | 208 | [[package]] 209 | name = "panic-rtt-target" 210 | version = "0.1.2" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "0d6ab67bc881453e4c90f958c657c1303670ea87bc1a16e87fd71a40f656dce9" 213 | dependencies = [ 214 | "cortex-m", 215 | "rtt-target", 216 | ] 217 | 218 | [[package]] 219 | name = "panic-semihosting" 220 | version = "0.6.0" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "ee8a3e1233d9073d76a870223512ce4eeea43c067a94a445c13bd6d792d7b1ab" 223 | dependencies = [ 224 | "cortex-m", 225 | "cortex-m-semihosting", 226 | ] 227 | 228 | [[package]] 229 | name = "paste" 230 | version = "1.0.14" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" 233 | 234 | [[package]] 235 | name = "proc-macro-error" 236 | version = "1.0.4" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 239 | dependencies = [ 240 | "proc-macro-error-attr", 241 | "proc-macro2", 242 | "quote", 243 | "syn 1.0.109", 244 | "version_check", 245 | ] 246 | 247 | [[package]] 248 | name = "proc-macro-error-attr" 249 | version = "1.0.4" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 252 | dependencies = [ 253 | "proc-macro2", 254 | "quote", 255 | "version_check", 256 | ] 257 | 258 | [[package]] 259 | name = "proc-macro2" 260 | version = "1.0.69" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 263 | dependencies = [ 264 | "unicode-ident", 265 | ] 266 | 267 | [[package]] 268 | name = "quote" 269 | version = "1.0.33" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 272 | dependencies = [ 273 | "proc-macro2", 274 | ] 275 | 276 | [[package]] 277 | name = "rtt-target" 278 | version = "0.3.1" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b" 281 | dependencies = [ 282 | "cortex-m", 283 | "ufmt-write", 284 | ] 285 | 286 | [[package]] 287 | name = "rustc_version" 288 | version = "0.2.3" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 291 | dependencies = [ 292 | "semver", 293 | ] 294 | 295 | [[package]] 296 | name = "semver" 297 | version = "0.9.0" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 300 | dependencies = [ 301 | "semver-parser", 302 | ] 303 | 304 | [[package]] 305 | name = "semver-parser" 306 | version = "0.7.0" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 309 | 310 | [[package]] 311 | name = "stable_deref_trait" 312 | version = "1.2.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 315 | 316 | [[package]] 317 | name = "stm32h7" 318 | version = "0.15.1" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "362f288cd8341e9209587b889c385f323e82fc237b60c272868965bb879bb9b1" 321 | dependencies = [ 322 | "bare-metal 1.0.0", 323 | "cortex-m", 324 | "cortex-m-rt", 325 | "vcell", 326 | ] 327 | 328 | [[package]] 329 | name = "stm32h7-boot" 330 | version = "0.1.0" 331 | dependencies = [ 332 | "cortex-m", 333 | "cortex-m-rt", 334 | "defmt", 335 | "defmt-rtt", 336 | "embedded-storage", 337 | "fugit", 338 | "panic-halt", 339 | "panic-itm", 340 | "panic-probe", 341 | "panic-rtt-target", 342 | "panic-semihosting", 343 | "rtt-target", 344 | "stm32h7xx-hal", 345 | ] 346 | 347 | [[package]] 348 | name = "stm32h7xx-hal" 349 | version = "0.15.1" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "e08bcfbdbe4458133f2fd55994a5c4f1b4bf28084f0218e93cdbc19d7c70219f" 352 | dependencies = [ 353 | "bare-metal 1.0.0", 354 | "cast", 355 | "cortex-m", 356 | "embedded-dma", 357 | "embedded-hal", 358 | "embedded-storage", 359 | "fugit", 360 | "nb 1.1.0", 361 | "paste", 362 | "stm32h7", 363 | "void", 364 | ] 365 | 366 | [[package]] 367 | name = "syn" 368 | version = "1.0.109" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 371 | dependencies = [ 372 | "proc-macro2", 373 | "quote", 374 | "unicode-ident", 375 | ] 376 | 377 | [[package]] 378 | name = "syn" 379 | version = "2.0.39" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" 382 | dependencies = [ 383 | "proc-macro2", 384 | "quote", 385 | "unicode-ident", 386 | ] 387 | 388 | [[package]] 389 | name = "thiserror" 390 | version = "1.0.50" 391 | source = "registry+https://github.com/rust-lang/crates.io-index" 392 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 393 | dependencies = [ 394 | "thiserror-impl", 395 | ] 396 | 397 | [[package]] 398 | name = "thiserror-impl" 399 | version = "1.0.50" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 402 | dependencies = [ 403 | "proc-macro2", 404 | "quote", 405 | "syn 2.0.39", 406 | ] 407 | 408 | [[package]] 409 | name = "ufmt-write" 410 | version = "0.1.0" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" 413 | 414 | [[package]] 415 | name = "unicode-ident" 416 | version = "1.0.12" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 419 | 420 | [[package]] 421 | name = "vcell" 422 | version = "0.1.3" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 425 | 426 | [[package]] 427 | name = "version_check" 428 | version = "0.9.4" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 431 | 432 | [[package]] 433 | name = "void" 434 | version = "1.0.2" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 437 | 438 | [[package]] 439 | name = "volatile-register" 440 | version = "0.2.2" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" 443 | dependencies = [ 444 | "vcell", 445 | ] 446 | -------------------------------------------------------------------------------- /boards/lpc55s69/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "asraw" 7 | version = "0.1.0" 8 | 9 | [[package]] 10 | name = "atomic-polyfill" 11 | version = "0.1.11" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" 14 | dependencies = [ 15 | "critical-section", 16 | ] 17 | 18 | [[package]] 19 | name = "autocfg" 20 | version = "1.1.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 23 | 24 | [[package]] 25 | name = "bare-metal" 26 | version = "0.2.5" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 29 | dependencies = [ 30 | "rustc_version 0.2.3", 31 | ] 32 | 33 | [[package]] 34 | name = "bitfield" 35 | version = "0.13.2" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 38 | 39 | [[package]] 40 | name = "bitflags" 41 | version = "1.3.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 44 | 45 | [[package]] 46 | name = "block-buffer" 47 | version = "0.9.0" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 50 | dependencies = [ 51 | "generic-array", 52 | ] 53 | 54 | [[package]] 55 | name = "block-buffer" 56 | version = "0.10.4" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 59 | dependencies = [ 60 | "generic-array", 61 | ] 62 | 63 | [[package]] 64 | name = "boot" 65 | version = "0.1.0" 66 | dependencies = [ 67 | "asraw", 68 | "heapless", 69 | "sha2", 70 | "storage", 71 | ] 72 | 73 | [[package]] 74 | name = "byteorder" 75 | version = "1.5.0" 76 | source = "registry+https://github.com/rust-lang/crates.io-index" 77 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 78 | 79 | [[package]] 80 | name = "cfg-if" 81 | version = "1.0.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 84 | 85 | [[package]] 86 | name = "cipher" 87 | version = "0.3.0" 88 | source = "registry+https://github.com/rust-lang/crates.io-index" 89 | checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" 90 | dependencies = [ 91 | "generic-array", 92 | ] 93 | 94 | [[package]] 95 | name = "cortex-m" 96 | version = "0.7.7" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" 99 | dependencies = [ 100 | "bare-metal", 101 | "bitfield", 102 | "critical-section", 103 | "embedded-hal", 104 | "volatile-register", 105 | ] 106 | 107 | [[package]] 108 | name = "cortex-m-rt" 109 | version = "0.6.15" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "454f278bf469e2de0a4d22ea019d169d8944f86957c8207a39e3f66c32be2fc6" 112 | dependencies = [ 113 | "cortex-m-rt-macros", 114 | "r0", 115 | ] 116 | 117 | [[package]] 118 | name = "cortex-m-rt-macros" 119 | version = "0.6.15" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "c8e3aa52243e26f5922fa522b0814019e0c98fc567e2756d715dce7ad7a81f49" 122 | dependencies = [ 123 | "proc-macro2", 124 | "quote", 125 | "syn 1.0.109", 126 | ] 127 | 128 | [[package]] 129 | name = "cortex-m-semihosting" 130 | version = "0.3.7" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc" 133 | dependencies = [ 134 | "cortex-m", 135 | ] 136 | 137 | [[package]] 138 | name = "cortex-m-semihosting" 139 | version = "0.5.0" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" 142 | dependencies = [ 143 | "cortex-m", 144 | ] 145 | 146 | [[package]] 147 | name = "cpufeatures" 148 | version = "0.2.11" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" 151 | dependencies = [ 152 | "libc", 153 | ] 154 | 155 | [[package]] 156 | name = "critical-section" 157 | version = "1.1.2" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" 160 | 161 | [[package]] 162 | name = "crypto-common" 163 | version = "0.1.6" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 166 | dependencies = [ 167 | "generic-array", 168 | "typenum", 169 | ] 170 | 171 | [[package]] 172 | name = "defmt" 173 | version = "0.3.5" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "a8a2d011b2fee29fb7d659b83c43fce9a2cb4df453e16d441a51448e448f3f98" 176 | dependencies = [ 177 | "bitflags", 178 | "defmt-macros", 179 | ] 180 | 181 | [[package]] 182 | name = "defmt-macros" 183 | version = "0.3.6" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "54f0216f6c5acb5ae1a47050a6645024e6edafc2ee32d421955eccfef12ef92e" 186 | dependencies = [ 187 | "defmt-parser", 188 | "proc-macro-error", 189 | "proc-macro2", 190 | "quote", 191 | "syn 2.0.38", 192 | ] 193 | 194 | [[package]] 195 | name = "defmt-parser" 196 | version = "0.3.3" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "269924c02afd7f94bc4cecbfa5c379f6ffcf9766b3408fe63d22c728654eccd0" 199 | dependencies = [ 200 | "thiserror", 201 | ] 202 | 203 | [[package]] 204 | name = "defmt-rtt" 205 | version = "0.4.0" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "609923761264dd99ed9c7d209718cda4631c5fe84668e0f0960124cbb844c49f" 208 | dependencies = [ 209 | "critical-section", 210 | "defmt", 211 | ] 212 | 213 | [[package]] 214 | name = "digest" 215 | version = "0.9.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 218 | dependencies = [ 219 | "generic-array", 220 | ] 221 | 222 | [[package]] 223 | name = "digest" 224 | version = "0.10.7" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 227 | dependencies = [ 228 | "block-buffer 0.10.4", 229 | "crypto-common", 230 | ] 231 | 232 | [[package]] 233 | name = "embedded-hal" 234 | version = "0.2.7" 235 | source = "registry+https://github.com/rust-lang/crates.io-index" 236 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 237 | dependencies = [ 238 | "nb 0.1.3", 239 | "void", 240 | ] 241 | 242 | [[package]] 243 | name = "embedded-time" 244 | version = "0.12.1" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" 247 | dependencies = [ 248 | "num", 249 | ] 250 | 251 | [[package]] 252 | name = "generic-array" 253 | version = "0.14.7" 254 | source = "registry+https://github.com/rust-lang/crates.io-index" 255 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 256 | dependencies = [ 257 | "typenum", 258 | "version_check", 259 | ] 260 | 261 | [[package]] 262 | name = "hash32" 263 | version = "0.2.1" 264 | source = "registry+https://github.com/rust-lang/crates.io-index" 265 | checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 266 | dependencies = [ 267 | "byteorder", 268 | ] 269 | 270 | [[package]] 271 | name = "heapless" 272 | version = "0.7.16" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "db04bc24a18b9ea980628ecf00e6c0264f3c1426dac36c00cb49b6fbad8b0743" 275 | dependencies = [ 276 | "atomic-polyfill", 277 | "hash32", 278 | "rustc_version 0.4.0", 279 | "spin", 280 | "stable_deref_trait", 281 | ] 282 | 283 | [[package]] 284 | name = "libc" 285 | version = "0.2.149" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" 288 | 289 | [[package]] 290 | name = "lock_api" 291 | version = "0.4.11" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" 294 | dependencies = [ 295 | "autocfg", 296 | "scopeguard", 297 | ] 298 | 299 | [[package]] 300 | name = "lpc55-hal" 301 | version = "0.3.0" 302 | dependencies = [ 303 | "block-buffer 0.9.0", 304 | "cipher", 305 | "cortex-m", 306 | "digest 0.9.0", 307 | "embedded-hal", 308 | "embedded-time", 309 | "generic-array", 310 | "lpc55-pac", 311 | "nb 1.1.0", 312 | "rand_core", 313 | "usb-device", 314 | "vcell", 315 | "void", 316 | ] 317 | 318 | [[package]] 319 | name = "lpc55-pac" 320 | version = "0.4.1" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "cf1b5b32d313af526145882f5115a55177f479e9328ca667a84aaaa1ae6d65d3" 323 | dependencies = [ 324 | "cortex-m", 325 | "cortex-m-rt", 326 | "vcell", 327 | ] 328 | 329 | [[package]] 330 | name = "mcuboot-lpc55s69" 331 | version = "0.1.0" 332 | dependencies = [ 333 | "asraw", 334 | "boot", 335 | "byteorder", 336 | "cortex-m", 337 | "cortex-m-rt", 338 | "cortex-m-semihosting 0.5.0", 339 | "defmt", 340 | "defmt-rtt", 341 | "embedded-hal", 342 | "embedded-time", 343 | "lpc55-hal", 344 | "panic-halt", 345 | "panic-probe", 346 | "panic-semihosting", 347 | "storage", 348 | ] 349 | 350 | [[package]] 351 | name = "nb" 352 | version = "0.1.3" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 355 | dependencies = [ 356 | "nb 1.1.0", 357 | ] 358 | 359 | [[package]] 360 | name = "nb" 361 | version = "1.1.0" 362 | source = "registry+https://github.com/rust-lang/crates.io-index" 363 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 364 | 365 | [[package]] 366 | name = "num" 367 | version = "0.3.1" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" 370 | dependencies = [ 371 | "num-complex", 372 | "num-integer", 373 | "num-iter", 374 | "num-rational", 375 | "num-traits", 376 | ] 377 | 378 | [[package]] 379 | name = "num-complex" 380 | version = "0.3.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" 383 | dependencies = [ 384 | "num-traits", 385 | ] 386 | 387 | [[package]] 388 | name = "num-integer" 389 | version = "0.1.45" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 392 | dependencies = [ 393 | "autocfg", 394 | "num-traits", 395 | ] 396 | 397 | [[package]] 398 | name = "num-iter" 399 | version = "0.1.43" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" 402 | dependencies = [ 403 | "autocfg", 404 | "num-integer", 405 | "num-traits", 406 | ] 407 | 408 | [[package]] 409 | name = "num-rational" 410 | version = "0.3.2" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 413 | dependencies = [ 414 | "autocfg", 415 | "num-integer", 416 | "num-traits", 417 | ] 418 | 419 | [[package]] 420 | name = "num-traits" 421 | version = "0.2.17" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" 424 | dependencies = [ 425 | "autocfg", 426 | ] 427 | 428 | [[package]] 429 | name = "panic-halt" 430 | version = "0.2.0" 431 | source = "registry+https://github.com/rust-lang/crates.io-index" 432 | checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" 433 | 434 | [[package]] 435 | name = "panic-probe" 436 | version = "0.3.1" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "aa6fa5645ef5a760cd340eaa92af9c1ce131c8c09e7f8926d8a24b59d26652b9" 439 | dependencies = [ 440 | "cortex-m", 441 | "defmt", 442 | ] 443 | 444 | [[package]] 445 | name = "panic-semihosting" 446 | version = "0.5.6" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec" 449 | dependencies = [ 450 | "cortex-m", 451 | "cortex-m-semihosting 0.3.7", 452 | ] 453 | 454 | [[package]] 455 | name = "proc-macro-error" 456 | version = "1.0.4" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 459 | dependencies = [ 460 | "proc-macro-error-attr", 461 | "proc-macro2", 462 | "quote", 463 | "syn 1.0.109", 464 | "version_check", 465 | ] 466 | 467 | [[package]] 468 | name = "proc-macro-error-attr" 469 | version = "1.0.4" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 472 | dependencies = [ 473 | "proc-macro2", 474 | "quote", 475 | "version_check", 476 | ] 477 | 478 | [[package]] 479 | name = "proc-macro2" 480 | version = "1.0.69" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" 483 | dependencies = [ 484 | "unicode-ident", 485 | ] 486 | 487 | [[package]] 488 | name = "quote" 489 | version = "1.0.33" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" 492 | dependencies = [ 493 | "proc-macro2", 494 | ] 495 | 496 | [[package]] 497 | name = "r0" 498 | version = "0.2.2" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" 501 | 502 | [[package]] 503 | name = "rand_core" 504 | version = "0.6.4" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 507 | 508 | [[package]] 509 | name = "rustc_version" 510 | version = "0.2.3" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 513 | dependencies = [ 514 | "semver 0.9.0", 515 | ] 516 | 517 | [[package]] 518 | name = "rustc_version" 519 | version = "0.4.0" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 522 | dependencies = [ 523 | "semver 1.0.20", 524 | ] 525 | 526 | [[package]] 527 | name = "scopeguard" 528 | version = "1.2.0" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 531 | 532 | [[package]] 533 | name = "semver" 534 | version = "0.9.0" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 537 | dependencies = [ 538 | "semver-parser", 539 | ] 540 | 541 | [[package]] 542 | name = "semver" 543 | version = "1.0.20" 544 | source = "registry+https://github.com/rust-lang/crates.io-index" 545 | checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" 546 | 547 | [[package]] 548 | name = "semver-parser" 549 | version = "0.7.0" 550 | source = "registry+https://github.com/rust-lang/crates.io-index" 551 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 552 | 553 | [[package]] 554 | name = "sha2" 555 | version = "0.10.8" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 558 | dependencies = [ 559 | "cfg-if", 560 | "cpufeatures", 561 | "digest 0.10.7", 562 | ] 563 | 564 | [[package]] 565 | name = "spin" 566 | version = "0.9.8" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 569 | dependencies = [ 570 | "lock_api", 571 | ] 572 | 573 | [[package]] 574 | name = "stable_deref_trait" 575 | version = "1.2.0" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 578 | 579 | [[package]] 580 | name = "storage" 581 | version = "0.1.0" 582 | 583 | [[package]] 584 | name = "syn" 585 | version = "1.0.109" 586 | source = "registry+https://github.com/rust-lang/crates.io-index" 587 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 588 | dependencies = [ 589 | "proc-macro2", 590 | "quote", 591 | "unicode-ident", 592 | ] 593 | 594 | [[package]] 595 | name = "syn" 596 | version = "2.0.38" 597 | source = "registry+https://github.com/rust-lang/crates.io-index" 598 | checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" 599 | dependencies = [ 600 | "proc-macro2", 601 | "quote", 602 | "unicode-ident", 603 | ] 604 | 605 | [[package]] 606 | name = "thiserror" 607 | version = "1.0.50" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" 610 | dependencies = [ 611 | "thiserror-impl", 612 | ] 613 | 614 | [[package]] 615 | name = "thiserror-impl" 616 | version = "1.0.50" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" 619 | dependencies = [ 620 | "proc-macro2", 621 | "quote", 622 | "syn 2.0.38", 623 | ] 624 | 625 | [[package]] 626 | name = "typenum" 627 | version = "1.17.0" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 630 | 631 | [[package]] 632 | name = "unicode-ident" 633 | version = "1.0.12" 634 | source = "registry+https://github.com/rust-lang/crates.io-index" 635 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 636 | 637 | [[package]] 638 | name = "usb-device" 639 | version = "0.2.9" 640 | source = "registry+https://github.com/rust-lang/crates.io-index" 641 | checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508" 642 | 643 | [[package]] 644 | name = "vcell" 645 | version = "0.1.3" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 648 | 649 | [[package]] 650 | name = "version_check" 651 | version = "0.9.4" 652 | source = "registry+https://github.com/rust-lang/crates.io-index" 653 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 654 | 655 | [[package]] 656 | name = "void" 657 | version = "1.0.2" 658 | source = "registry+https://github.com/rust-lang/crates.io-index" 659 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 660 | 661 | [[package]] 662 | name = "volatile-register" 663 | version = "0.2.2" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" 666 | dependencies = [ 667 | "vcell", 668 | ] 669 | --------------------------------------------------------------------------------