nrf52840
The nrf52840
example uses a maker-diary board. It has a custom led configuration.
Note:
- If you're using a different version of the board, you'll probably need to edit your firmware's
partition-addresses
to accommodate for differences.- Just make sure you don't change the names of files or the folder structure, as cargo xtask looks for these file/folder names.
Partitioning:
The first step in integrating rustBoot is flash-memory partitioning
i.e. we divide the nrf52840
's flash-memory into 4 partitions, taking into account the geometry of the flash memory.
You can read more about
mcu
partitioning here
In this example, we'll be using the following partitioning scheme. You can locate these constants in the constants module
#![allow(unused)] fn main() { #[cfg(feature = "nrf52840")] pub const SECTOR_SIZE: usize = 0x1000; #[cfg(feature = "nrf52840")] pub const PARTITION_SIZE: usize = 0x28000; #[cfg(feature = "nrf52840")] pub const BOOT_PARTITION_ADDRESS: usize = 0x2f000; #[cfg(feature = "nrf52840")] pub const SWAP_PARTITION_ADDRESS: usize = 0x57000; #[cfg(feature = "nrf52840")] pub const UPDATE_PARTITION_ADDRESS: usize = 0x58000; }
RUSTBOOT partition:
contains the bootloader (its code and data) and a (test) public-key embedded as part of the bootloader image, starts at address0x0
.BOOT partition:
contains boot firmware, starts at addressPARTITION_BOOT_ADDRESS
.UPDATE partition:
contains update firmware, starts at addressUPDATE_PARTITION_ADDRESS
. The boot firmware is responsible for downloading and installing the update firmware into this partition via a secure channel.SWAP partition:
is the temporary swap space, starts at addressSWAP_PARTITION_ADDRESS
.
Compiling, Signing and Programming:
Now that we have properly partitioned the nrf52840
's on-board flash-memory, the next step is - compiling, signing and programming
We will compile the following
- bootloader
- boot and update firmware
sign both pieces of firmware with a (test) private-key and finally create valid rustBoot mcu-images
i.e. signed boot and update firmware images.
Note:
- the
ecc256.der
file contains a public-key and a private-key, the first 64 bytes being the public-key and remaining 32 bytes make up the private-key.- This is a test key file and is to be used for testing purposes only.
Compiling, signing and programming can be performed via a single command
cargo nrf52840 build-sign-flash rustBoot
Note:
- The
updt-ver
number must be greater thanboot-ver
.
This will build, sign and flash all 3 packages (i.e. bootloader + boot-fw + update-fw) onto the board.
Note:
- The corresponding public-key is embedded in the bootloader's source.
- In order to test this example, you'll have to install a couple of pre-requisites as it uses probe-run to flash the binary.
cargo install probe-rs-cli
cargo install cargo-flash
cargo install cargo-binutils
Here's the command line output that should be produced.
PS C:\Users\Nil\devspace\rust\projects\rb> cargo nrf52840 build-sign-flash rustBoot 1234 1235
Finished dev [unoptimized + debuginfo] target(s) in 0.06s
Running `target/debug/xtask nrf52840 build-sign-flash rustBoot 1234 1235`
$ cargo build --release
Compiling rand_core v0.6.3
Compiling subtle v2.4.1
Compiling nb v1.0.0
Compiling cfg-if v1.0.0
...
...
Compiling rustBoot-hal v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/hal)
Compiling rustBoot-update v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/update)
Compiling nrf52840_bootfw v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/firmware/nrf52840/boot_fw_blinky_green)
Finished release [optimized] target(s) in 10.60s
$ cargo build --release
Compiling nrf52840_updtfw v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/firmware/nrf52840/updt_fw_blinky_red)
Finished release [optimized] target(s) in 0.43s
$ cargo build --release
Compiling rand_core v0.6.3
Compiling subtle v2.4.1
Compiling cfg-if v1.0.0
Compiling nb v1.0.0
...
...
Compiling rustBoot-hal v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/hal)
Compiling rustBoot-update v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/update)
Compiling nrf52840 v0.1.0 (/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/bootloaders/nrf52840)
Finished release [optimized] target(s) in 10.96s
$ rust-objcopy -I elf32-littlearm ../../target/thumbv7em-none-eabihf/release/nrf52840_bootfw -O binary nrf52840_bootfw.bin
$ rust-objcopy -I elf32-littlearm ../../target/thumbv7em-none-eabihf/release/nrf52840_updtfw -O binary nrf52840_updtfw.bin
$ cargo run mcu-image ../boards/sign_images/signed_images/nrf52840_bootfw.bin nistp256 ../boards/sign_images/keygen/ecc256.der 1234
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/target/debug/rbsigner mcu-image ../boards/sign_images/signed_images/nrf52840_bootfw.bin nistp256 ../boards/sign_images/keygen/ecc256.der 1234`
Image type: mcu-image
Curve type: nistp256
Input image: nrf52840_bootfw.bin
Public key: ecc256.der
Image version: 1234
Output image: nrf52840_bootfw_v1234_signed.bin
Calculating sha256 digest...
Signing the firmware...
Done.
Output image successfully created with 1696 bytes.
$ cargo run mcu-image ../boards/sign_images/signed_images/nrf52840_updtfw.bin nistp256 ../boards/sign_images/keygen/ecc256.der 1235
Finished dev [unoptimized + debuginfo] target(s) in 0.03s
Running `/Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/target/debug/rbsigner mcu-image ../boards/sign_images/signed_images/nrf52840_updtfw.bin nistp256 ../boards/sign_images/keygen/ecc256.der 1235`
Image type: mcu-image
Curve type: nistp256
Input image: nrf52840_updtfw.bin
Public key: ecc256.der
Image version: 1235
Output image: nrf52840_updtfw_v1235_signed.bin
Calculating sha256 digest...
Signing the firmware...
Done.
Output image successfully created with 1724 bytes.
$ probe-rs-cli erase --chip nRF52840_xxAA
$ probe-rs-cli download --format Bin --base-address 0x2f000 --chip nRF52840_xxAA nrf52840_bootfw_v1234_signed.bin
Erasing sectors ✔ [00:00:00] [##########] 4.00KiB/ 4.00KiB @ 15.97KiB/s (eta 0s )
Programming pages ✔ [00:00:00] [##########] 4.00KiB/ 4.00KiB @ 6.77KiB/s (eta 0s )
Finished in 0.73s
$ probe-rs-cli download --format Bin --base-address 0x58000 --chip nRF52840_xxAA nrf52840_updtfw_v1235_signed.bin
Erasing sectors ✔ [00:00:00] [##########] 4.00KiB/ 4.00KiB @ 16.34KiB/s (eta 0s )
Programming pages ✔ [00:00:00] [##########] 4.00KiB/ 4.00KiB @ 6.86KiB/s (eta 0s )
Finished in 0.713s
$ cargo flash --chip nRF52840_xxAA --release
Finished release [optimized] target(s) in 0.06s
Flashing /Users/nihal.pasham/devspace/rust/projects/prod/rustBoot/boards/target/thumbv7em-none-eabihf/release/nrf52840
Erasing sectors ✔ [00:00:01] [##########] 44.00KiB/44.00KiB @ 25.20KiB/s (eta 0s )
Programming pages ✔ [00:00:03] [##########] 44.00KiB/44.00KiB @ 5.62KiB/s (eta 0s )
Finished in 4.808s
Verifying:
blinky leds
are used to confirm that rustBoot works as expected. Here's the flow
- Upon supplying power to the board, rustBoot takes over
validates
the firmware image stored in theBOOT
partition i.e.- verifies the signature attached against a known public key stored in the rustBoot image.
- If the signature checks out, rustBoot boots into the bootfw and blinks a
green-led
for a few seconds,- post which, the boot firmware triggers the update and performs a system reset.
- Upon reset, the rustBoot again takes over
- validates the firmware image stored in the UPDATE partition
swaps
the contents of theBOOT
and theUPDATE
partitions- marks the new firmware in the
BOOT
partition as in stateSTATE_TESTING
- boots into the UPDATE'd firmware
- Now that execution-control has been transferred to the UPDATE'd firmware
- it will attempt to blink a
red-led
- and set a
confirmation flag
to indicate that the update was successful. - post which, it continuously blinks a
red-led
.
- it will attempt to blink a