![]() |
Morse Micro IoT SDK
2.9.7
|
Example bootloader to boot and update application securely.
The software update is done in 2 stages.
This step is performed by the application and is application specific. The application downloads the software image using any means possible and then authenticates it using any means possible - this is all application specific. The update image is in the morse MBIN file format. Once the software image has been successfully downloaded and authenticated, the application software needs to signal the bootloader that a new image is available for flashing. it does so by simply writing the path of the software image to config store key UPDATE_IMAGE. For added security the application also writes a SHA256 hash of the image to IMAGE_SIGNATURE key. Once this is done, the application simply reboots the CPU which causes the bootloader to execute.
To build a .mbin file for any application simply issue the following make command in the applications folder:
The result of the above command will be a .mbin file in the build/ directory for the application in addition to the .elf file.
This code implements stage 2. Once rebooted by the application, the CPU automatically executes the bootloader (this program) which is in the boot region of flash. The bootloader sees that there is an UPDATE_IMAGE key in config store and proceeds to verify the image pointed to by the key using the SHA256 algorithm and compares the result with the hash in the IMAGE_SIGNATURE key. If the hash matches it then proceeds with flashing the image into the application code area of the flash. In case the checksum does not match the bootloader writes an error code into the config store and jumps back into the old application image without performing the software update. Once the image has been successfully flashed the bootloader transfers control to the new application image.
If no UPDATE_IMAGE key was found, the bootloader simply jumps to the current application image in flash.
In addition to the above the bootloader performs some sanity checks like checking how many times the update was attempted and failed in order to prevent the bootloader from getting stuck in an infinite update loop in the event of a faulty hardware (or software image).
Definition in file bootloader.c.
#include <stdio.h>#include <stdint.h>#include <stdbool.h>#include <string.h>#include <endian.h>#include <sys/unistd.h>#include <sys/fcntl.h>#include <sys/errno.h>#include "sha256.h"#include "mmhal_flash.h"#include "mmconfig.h"#include "mmhal.h"#include "mmosal.h"#include "puff.h"#include "mbin.h"
Go to the source code of this file.
Macros | |
| #define | MAX_UPDATE_ATTEMPTS 10 |
| Maximum number of times we attempt to update before giving up. More... | |
| #define | MAX_SEGMENT_SIZE 32768 |
| Maximum size of a segment, set to 32768. More... | |
Enumerations | |
| enum | bootloader_return_codes { BOOTLOADER_OK = 0 , BOOTLOADER_ERR_FILE_NOT_FOUND , BOOTLOADER_ERR_SIGNATURE_NOT_FOUND , BOOTLOADER_ERR_FILE_VERIFICATION_FAILED , BOOTLOADER_ERR_INVALID_FILE , BOOTLOADER_ERR_FILE_CORRUPT , BOOTLOADER_ERR_ERASE_FAILED , BOOTLOADER_ERR_PROGRAM_FAILED , BOOTLOADER_ERR_TOO_MANY_ATTEMPTS , BOOTLOADER_ERR_FILE_DECOMPRESSION } |
| Bootloader return codes. More... | |
Functions | |
| static void | delay_ms (uint32_t approx_delay_ms) |
| Implements a delay of approximately the duration specified. More... | |
| static void | blink_error_code (int code) |
| Blinks the hardware error LED to indicate the error code. More... | |
| static void | update_failed (int code) |
| Called when multiple attempts to update failed, must not return. More... | |
| static void | erase_application_area (void) |
| This function erases the entire application flash region. More... | |
| static int | read_segment_header (int fd, struct mbin_tlv_hdr *seg_hdr) |
| Loads the segment header from file. More... | |
| static int | read_uint32 (int fd, uint32_t *val) |
| Loads a 32 bit integer from file and converts to host endian. More... | |
| static int | load_and_flash_mbin (const char *fname, bool make_changes) |
| Loads and flashes the image. More... | |
| static int | verify_signature (const char *fname) |
| Verifies the signature of the file. More... | |
| static void | check_update () |
| Check for an update, if an update is found, perform it. More... | |
| int | main (void) |
| The bootloader entry point. More... | |
Variables | |
| uint8_t | application_start |
| Start of Application region in flash. | |
| uint8_t | application_end |
| End of Application region in flash. | |
| static uint8_t | segment_buffer [MAX_SEGMENT_SIZE] |
| Temporary buffer for loading segments. More... | |
| static uint8_t | deflate_buffer [MAX_SEGMENT_SIZE] |
| Temporary buffer for deflating segments. More... | |
| #define MAX_SEGMENT_SIZE 32768 |
Maximum size of a segment, set to 32768.
Definition at line 78 of file bootloader.c.
| #define MAX_UPDATE_ATTEMPTS 10 |
Maximum number of times we attempt to update before giving up.
Definition at line 75 of file bootloader.c.
Bootloader return codes.
Definition at line 81 of file bootloader.c.
|
static |
Blinks the hardware error LED to indicate the error code.
| code | The error code to blink. |
Definition at line 130 of file bootloader.c.
|
static |
Check for an update, if an update is found, perform it.
Definition at line 550 of file bootloader.c.
|
static |
Implements a delay of approximately the duration specified.
| approx_delay_ms | The delay in ms. |
Definition at line 113 of file bootloader.c.
|
static |
This function erases the entire application flash region.
We erase everything in one go as we don't want to deal with overlapping segments in the MBIN file. If a segment overlaps we need to take care that we don't erase the same flash block twice (or we lose the data data for the previous segment due to the overlap). We avoid this issue by erasing everything in one go at the start.
Definition at line 184 of file bootloader.c.
|
static |
Loads and flashes the image.
| fname | MBIN file to load |
| make_changes | If make_changes is false then flash will not be written to |
Definition at line 263 of file bootloader.c.
| int main | ( | void | ) |
|
static |
Loads the segment header from file.
| fd | The file descriptor to read from |
| seg_hdr | Pointer to segment header to read data into |
Definition at line 218 of file bootloader.c.
|
static |
Loads a 32 bit integer from file and converts to host endian.
| fd | The file descriptor to read from |
| val | Pointer to variable to read data into |
Definition at line 241 of file bootloader.c.
|
static |
Called when multiple attempts to update failed, must not return.
This function could try rebooting after a fixed delay and the update process can be retried by the bootloader. However the delay should be sufficiently large (several minutes at least) as it is likely that whatever caused us to fail will happen again, so spamming the flash with multiple attempts is not a good idea.
We usually end up in this function if we had a hardware failure, like a flash failure. So the problem is likely to happen again and will possibly get worse with each attempt.
We do not end up in this function if sanity checks (Like image checksum) prior to updating failed. If that happens we simply continue to the existing application with an error code stored in config store. Once the flash is erased, any failure will get us here.
| code | The error code, gets written to config store and blinked. |
Definition at line 164 of file bootloader.c.
|
static |
Verifies the signature of the file.
| fname | MBIN file to verify |
Definition at line 501 of file bootloader.c.
|
static |
Temporary buffer for deflating segments.
Definition at line 105 of file bootloader.c.
|
static |
Temporary buffer for loading segments.
Definition at line 102 of file bootloader.c.