|
1 |
| -# MCUboot-portenta-boot |
2 |
| -MCUBoot bootloader based on Mbed-OS for `PORTENTA_H7` target boards. |
| 1 | +<img src="https://content.arduino.cc/website/Arduino_logo_teal.svg" height="100" align="right" /> |
3 | 2 |
|
4 |
| -This application builds as a bootloader and should be used with the [corresponding core](https://github.com/bcmi-labs/ArduinoCore-mbed/tree/mcuboot). |
| 3 | +`MCUboot Arduino` |
| 4 | +================= |
| 5 | +MCUboot bootloader porting for Arduino [Mbed OS](https://os.mbed.com/docs/mbed-os/latest/introduction/index.html) based boards. |
5 | 6 |
|
6 |
| -## Prepare the board |
7 |
| -At boot time by default MCUBoot will check for 2 "FileBlockDevices" into the QSPI flash. To prepare and format the QSPI flash as needed run this [sketch](https://github.com/bcmi-labs/mcuboot-portenta-boot/blob/boot_sketch/tools/PortentaMCUBootQSPIFormat.ino) before switching to MCUBoot. |
| 7 | +The following boards are supported: |
| 8 | + * [PORTENTA_H7](https://store.arduino.cc/products/portenta-h7) |
8 | 9 |
|
9 |
| -## Upload MCUBoot bootloader |
10 |
| -Different ways are available to switch to the new bootloader: |
| 10 | +## :grey_question: What |
| 11 | +MCUboot provides secure boot for 32-bit microcontrollers. For a detailed description on what MCUboot does and how it works please read the [official documentaion](https://docs.mcuboot.com/). |
11 | 12 |
|
12 |
| -### JLink |
13 |
| -Using JFlash or JFlashLite is possible to upload the MCUBoot bootloader binary to the board. The MCUBoot bootloader is stored at flash address `0x08000000` |
| 13 | +## :zap: Main features |
| 14 | +### Signed and encrypted updates |
| 15 | +MCUboot has support for encrypting/decrypting images on-the-fly while upgrading; furthermore, before booting a Sketch, it will check if the computed signature is matching the one embedded in the image. |
| 16 | + |
| 17 | +### Confirm or revert updates |
| 18 | +After an update the new Sketch can update the content of the flash at runtime to mark itself as `OK`. MCUboot will then still choose to run it during the next boot. When this happens, the swap is made `permanent`. If this doesn’t happen, MCUboot will perform a `revert` swap during the next boot by swapping the image back into its original location, and attempting to boot the old Sketch. |
14 | 19 |
|
15 |
| -### Arduino Sketch |
16 |
| -Running this [sketch](https://github.com/bcmi-labs/mcuboot-portenta-boot/blob/boot_sketch/tools/PortentaMCUBootQSPIFormat.ino) will upload the last released MCUBoot bootloader to the board. |
| 20 | +### Sketch bootstrap |
| 21 | +If no valid image is found in the primary slot MCUboot will search a valid image in the secondary slot and if any it will load it inside the primary slot. |
17 | 22 |
|
18 |
| -## Keys customization |
19 |
| -The bootloder comes with a preloaded set of default keys for signing and encryption. !!!WARNING!!! The default keyset is public therefore is not safe to use them for production, they are included only for evaluation purpose. Keys can be manually regenerated and included in the build flow to provide a real security layer to custom projects. |
| 23 | +### Reset recovery |
| 24 | +If a reset occurs in the middle of a swap operation, the two images may be discontiguous in flash. MCUboot recovers from this condition by using the image trailers to determine how the image parts are distributed in flash and restarting the swap. |
20 | 25 |
|
| 26 | +### Backward compatible with default Arduino booloader |
| 27 | +If signing and encryption keys are not stored in flash alongside MCUboot, the Sketch signature verification is skipped and any valid Sketch can be booted. |
| 28 | + |
| 29 | +## :gear: How |
| 30 | +### Switch to MCUboot |
| 31 | +* Run this [Sketch](https://github.com/arduino/ArduinoCore-mbed/blob/master/libraries/STM32H747_System/examples/STM32H747_updateBootloader/STM32H747_updateBootloader.ino) to upload the latest released binary into your board |
| 32 | +* Flash the bootloader binary file with your preferred debugger @ flash address `0x08000000` |
| 33 | + |
| 34 | +### Enable signature and encryption |
| 35 | +By default signature verification and encryption support are disabled. To enable them you have to write your signature and encryption keys inside your board. |
| 36 | +In this project MCUboot is configured to support `ecdsa-p256` keys for both signature and encryption. |
| 37 | + |
| 38 | +To write the default keys in flash you can use this [Sketch](https://github.com/arduino/ArduinoCore-mbed/blob/master/libraries/STM32H747_System/examples/STM32H747_updateBootloader/STM32H747_updateBootloader.ino) |
| 39 | + |
| 40 | +:warning: WARNING :warning: The default keys are public therefore is not safe to use them for production, they are included only for evaluation purpose. |
| 41 | + |
| 42 | +### Customize signing and encryption keys |
| 43 | +You can use your preferred tool the generate your `ecdsa-p256` keys. With imgtool: |
21 | 44 | ```
|
22 | 45 | imgtool keygen -k ecsdsa-p256-signing-key.pem -t ecdsa-p256
|
23 | 46 | imgtool keygen -k ecsdsa-p256-encrypt-key.pem -t ecdsa-p256
|
24 |
| -imgtool getpub -k ecsdsa-p256-signing-key.pem > ecsdsa-p256-signing-key.c |
25 |
| -imgtool getpriv -k ecsdsa-p256-encrypt-key.pem > ecsda-p256-encrypt-key.c |
26 | 47 | ```
|
27 |
| - |
28 |
| -## Build from source |
29 |
| - |
| 48 | +The public signing key and the private encryption key have to be written in flash at this addresses: |
30 | 49 | ```
|
31 |
| -cd mcuboot-portenta-boot |
32 |
| -mbed config root . && mbed deploy |
33 |
| -mbed compile -m PORTENTA_H7_M7 -t GCC_ARM --profile=release --profile mbed-os/tools/profiles/extensions/lto.json |
| 50 | +signing key @ 0x8000300 |
| 51 | +encrypt key @ 0x8000400 |
34 | 52 | ```
|
| 53 | +To get this data from the generated pem files with imgtool: |
| 54 | +``` |
| 55 | +imgtool getpub -k ecsdsa-p256-signing-key.pem |
| 56 | +imgtool getpriv -k ecsdsa-p256-encrypt-key.pem |
| 57 | +``` |
| 58 | +Copy and paste the key data in this [Sketch](https://github.com/arduino/ArduinoCore-mbed/blob/master/libraries/STM32H747_System/examples/STM32H747_updateBootloader/STM32H747_updateBootloader.ino) and run it to flash the keys alongside the bootloader. |
35 | 59 |
|
36 |
| -## Memory Regions Overview |
37 |
| - |
38 |
| -The diagram below shows the default memory map configuration used for this mcuboot demo on the nRF52840. The nRF52840 has a total of 1MB of internal program flash. The following sections detail how the bounds of each memory region is configured. |
39 |
| - |
40 |
| - |
41 |
| - |
42 |
| -### Bootloader |
43 |
| -The bootloader (the application in this repository) lives in the first region of flash where the processor begins execution. The basic mcuboot bootloader does not implement any interfaces to receive updates. It simply looks at available application "slots". The application (or another bootloader) is responsible for loading application updates into a slot visible to the mcuboot bootloader. Update candidates are typically placed in the "secondary" flash region. |
44 |
| - |
45 |
| -The bootloader has a maximum size set by `target.restrict_size`. In this project the bootloader is restricted to a size of `0x20000` bytes. |
46 |
| - |
47 |
| -Upon bootup, mcuboot looks at two memory regions, one called the "primary slot" and the other called the "secondary slot", to determine if a firmware update is available and should be installed. |
48 |
| - |
49 |
| -### Primary Slot Region |
50 |
| - |
51 |
| -The **"primary slot"** region is typically located immediately following the end of the bootloader. The starting address of the primary slot can be configured using the parameter `mcuboot.primary-slot-address`. The primary slot begins with the application header and contains the bootable main application and trailer info. |
52 |
| - |
53 |
| -The primary slot typically ends where the "mcuboot scratch region" begins (see Scratch Space Region below). The size (and thus the end address) of the primary slot can be configured using the parameter `mcuboot.slot-size`. Note that this parameter also configures the expected size of the secondary slot region. |
54 |
| - |
55 |
| -In this project primary slot starts at flash address `0x080400000` and slot size is `0xC0000`. Scratch region by default is placed on the external QSPI flash using a "FileBlockDevice". |
56 |
| - |
57 |
| -**Note:** If your application uses internal flash for data storage (eg: KVStore), you must carefully configure the memory regions allocated to the primary slot, the scratch region, and your application to ensure there are no conflicts. |
58 |
| - |
59 |
| -#### Application Header Info |
60 |
| - |
61 |
| -The application header info section is at the beginning of the "primary memory slot". |
62 |
| - |
63 |
| -When deciding what to boot/update, the mcuboot bootloader looks at an installed application's header info, which is a special struct prepended to the application binary. It uses this header info to validate that there is a bootable image installed in the "slot". |
64 |
| - |
65 |
| -By default, this header is configured to be 4kB in size. This can be adjusted using the configuration parameter `mcuboot.header_size`. |
66 |
| - |
67 |
| -**However,** due to the way the FlashIAP block device currently works while erasing, the header_size should be configured to be the size of an erase sector (128kB in the case of an STM32H7). Erasing using the FlashIAPBlockDevice only works if the given address is erase-sector aligned! |
68 |
| - |
69 |
| -This header is prepended to the application binary during the signing process (explained later). |
70 |
| - |
71 |
| -#### Primary Application |
72 |
| - |
73 |
| -The primary application is the currently installed, bootable application and it must be buid with the [corresponding core](https://github.com/bcmi-labs/ArduinoCore-mbed/tree/mcuboot). |
74 |
| - |
75 |
| - |
76 |
| -#### Application TLV Trailers |
77 |
| - |
78 |
| -There are also type-length-value (TLV) encoded pieces of information following the application binary called the "application trailer". These TLV encoded values include things like a digital signature and SHA hash, among other things. Similar to the application header info, the TLV trailers are also appended to the application hex during signing. |
79 |
| - |
80 |
| -The space reserved for the application TLV trailers is determined from other configuration parameters. The TLV trailers reside in the memory between the **end** of the *primary application* and the **end** of the *primary slot*. |
81 |
| - |
82 |
| -ie: The TLV trailers start at `target.mbed_app_start + target.mbed_app_size` and end at `mcuboot.primary-slot-address + mcuboot.slot-size`. |
83 |
| - |
84 |
| -In our case, our configuration gives us: |
85 |
| - |
86 |
| -`target.mbed_app_start + target.mbed_app_size = = TLV start address` |
87 |
| - |
88 |
| -`mcuboot.primary-slot-address + mcuboot.slot-size = = TLV end address` |
| 60 | +### Create a signed and encrypted update Sketch |
| 61 | +To create a signed and encrypted Sketch an additional step is needed after the Sketch binary is generated. This additional step is done passing the binary through `imgtool`. The flags used by the board to create a secure Sketch are defined [here](https://github.com/arduino/ArduinoCore-mbed/blob/fa628e35011a92fb7e54fa6bfd9a69be33173bf8/boards.txt#L79-L86). The resulting command resembles as follows: |
| 62 | +``` |
| 63 | +imgtool sign --key ecdsa-p256-signing-key.pem --encrypt ecdsa-p256-encrypt-key.pem input.bin output.bin --align 32 --max-align 32 --version 1.2.3+4 --header-size 0x20000 --pad-header --slot-size 0x1E0000 |
| 64 | +``` |
89 | 65 |
|
90 |
| -`TLV region size = - = ` |
| 66 | +### Load an update sketch |
| 67 | +The bootloader exposes a DFU interface that can be used to upload a sketch in the QSPI flash of the board as a file. The upload process ends setting the pending flag to the update binary file and resetting the board. After reset MCUboot takes care of applying the update. |
| 68 | +``` |
| 69 | +dfu-util --device 0x2341:0x035b -D update.ino.bin -a2 --dfuse-address=0xA0000000:leave |
| 70 | +``` |
91 | 71 |
|
92 |
| -### Scratch Space Region |
| 72 | +### Confirm an update sketch |
| 73 | +MCUboot expects that every update have to be confirmed otherwise it will revert to the previous running sketch as soon as the board is resetted. To confirm a sketch you have to call `MCUboot::confirmSketch()` in your `setup()`. |
| 74 | +``` |
| 75 | +void setup() { |
| 76 | + ... |
| 77 | + |
| 78 | + if(applicationSelfCheck() == OK) { |
| 79 | + MCUboot::confirmSketch() |
| 80 | + } |
| 81 | + |
| 82 | + ... |
| 83 | +} |
| 84 | +``` |
93 | 85 |
|
94 |
| -If configured as such, mcuboot can perform a "swap" update where it will copy the existing main application into the secondary memory region and the update candidate into the main application region. This allows mcuboot to revert the update in case of a serious firmware bug (ie: brick-proofs the update process). If the updated application fails to mark itself as "okay", mcuboot will revert the update upon the next boot cycle. |
| 86 | +### Flash is allocated |
| 87 | +The diagram below shows the default memory map configuration used for this project: |
95 | 88 |
|
96 |
| -To perform this kind of swap update, mcuboot requires a non-volatile "scratch" space in memory to store pieces of application code and update status information. This enables mcuboot to safely continue an update/revert procedure in the event of a power loss. |
| 89 | +``` |
| 90 | +INTERNAL FLASH QSPI FLASH |
| 91 | +
|
| 92 | +Slot 0 Scratch |
| 93 | +0x08020000 - 0x081FFFFF MBRBlockDevice partition 2 scratch.bin |
| 94 | + 0x08020000 header |
| 95 | + 0x08040000 Sketch Slot 1 |
| 96 | + 0x081E0000 trailer MBRBlockDevice partition 2 update.bin |
| 97 | +
|
| 98 | +Bootloader |
| 99 | +0x08000000 - 0x0801FFF |
| 100 | + 0x080002F0 bootloader id |
| 101 | + 0x08000300 signing key |
| 102 | + 0x08000400 encrypt key |
| 103 | + 0x0801F000 board data |
| 104 | +``` |
97 | 105 |
|
98 |
| -The scratch region starting address may be specified with the configuration parameter, `mcuboot.scratch-address`. The size of the scratch space can be configured using `mcuboot.scratch-size` -- this value **must** be erase-sector aligned (ie: a multiple of the internal flash's eraseable size). |
| 106 | +### Build MCUboot from source |
| 107 | +``` |
| 108 | +mbed config root . && mbed deploy |
| 109 | +mbed compile -m PORTENTA_H7_M7 -t GCC_ARM --profile=release --profile mbed-os/tools/profiles/extensions/lto.json |
| 110 | +``` |
99 | 111 |
|
100 |
| -For more advanced information about configuring the scratch space region, see the [mcuboot documentation on Image Slots](https://github.com/mcu-tools/mcuboot/blob/master/docs/design.md#image-slots). For more information on swap updates, see the [mcuboot documentation on Swap Updates](https://github.com/mcu-tools/mcuboot/blob/master/docs/design.md#image-swapping) |
| 112 | +### Debug |
101 | 113 |
|
102 |
| -### Secondary Slot Region |
| 114 | +1. LED |
| 115 | + - MCUboot operations: slot verify, copy, erase or swap the board LED will blink in violet (red+blue). |
| 116 | + - MCUboot idle: The board green LED will fade-in fade-out |
103 | 117 |
|
104 |
| -The **"secondary"** slot region is provided by you. Typically this is an external flash chip used for bulk data and firmware update storage. |
| 118 | +2. Serial |
| 119 | + - MCUboot debug prints are disabled by default. They can be enabled putting `BT_SEL` (`PI8`) pin `HIGH` or calling `MCUboot::bootDebug(1);` in your Sketch. |
105 | 120 |
|
106 |
| -The function, `mbed::BlockDevice* get_secondary_bd(void)` declared in `secondary_bd.h`, is used by mcuboot to retrieve the `BlockDevice` instance it will use for the secondary slot. You **must** implement this function to build the bootloader _and_ the bootable application! |
| 121 | +## :mag_right: Other resources |
107 | 122 |
|
108 |
| -The returned BlockDevice is expected to have a size equivalent to the configuration `mcuboot.slot-size` as mentioned previously. |
| 123 | +* [MCUboot repository](https://github.com/mcu-tools/mcuboot) |
| 124 | +* [MCUboot demo for nRF52840](https://github.com/AGlass0fMilk/mbed-mcuboot-demo) |
| 125 | +* [MCUboot documentation](https://docs.mcuboot.com/) |
0 commit comments