Morse Micro IoT SDK  2.9.7
bootloader.c File Reference

Detailed Description

Example bootloader to boot and update application securely.

Firmware Update Procedure

The software update is done in 2 stages.

Stage 1: Software download and Authentication

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:

make mbin -j4

The result of the above command will be a .mbin file in the build/ directory for the application in addition to the .elf file.

Note
You cannot generate a .mbin file for the bootloader itself.

Stage 2: Flashing the Software image

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"
Include dependency graph for bootloader.c:

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...
 

Macro Definition Documentation

◆ MAX_SEGMENT_SIZE

#define MAX_SEGMENT_SIZE   32768

Maximum size of a segment, set to 32768.

Definition at line 78 of file bootloader.c.

◆ MAX_UPDATE_ATTEMPTS

#define MAX_UPDATE_ATTEMPTS   10

Maximum number of times we attempt to update before giving up.

Definition at line 75 of file bootloader.c.

Enumeration Type Documentation

◆ bootloader_return_codes

Bootloader return codes.

Definition at line 81 of file bootloader.c.

Function Documentation

◆ blink_error_code()

static void blink_error_code ( int  code)
static

Blinks the hardware error LED to indicate the error code.

Parameters
codeThe error code to blink.

Definition at line 130 of file bootloader.c.

◆ check_update()

static void check_update ( )
static

Check for an update, if an update is found, perform it.

Definition at line 550 of file bootloader.c.

◆ delay_ms()

static void delay_ms ( uint32_t  approx_delay_ms)
static

Implements a delay of approximately the duration specified.

Parameters
approx_delay_msThe delay in ms.

Definition at line 113 of file bootloader.c.

◆ erase_application_area()

static void erase_application_area ( void  )
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.

◆ load_and_flash_mbin()

static int load_and_flash_mbin ( const char *  fname,
bool  make_changes 
)
static

Loads and flashes the image.

Parameters
fnameMBIN file to load
make_changesIf make_changes is false then flash will not be written to
Returns
BOOTLOADER_OK on success, else error code

Definition at line 263 of file bootloader.c.

◆ main()

int main ( void  )

The bootloader entry point.

Returns
Does not return

Definition at line 620 of file bootloader.c.

◆ read_segment_header()

static int read_segment_header ( int  fd,
struct mbin_tlv_hdr seg_hdr 
)
static

Loads the segment header from file.

Parameters
fdThe file descriptor to read from
seg_hdrPointer to segment header to read data into
Returns
BOOTLOADER_OK on success, else error code

Definition at line 218 of file bootloader.c.

◆ read_uint32()

static int read_uint32 ( int  fd,
uint32_t *  val 
)
static

Loads a 32 bit integer from file and converts to host endian.

Parameters
fdThe file descriptor to read from
valPointer to variable to read data into
Returns
BOOTLOADER_OK on success, else error code

Definition at line 241 of file bootloader.c.

◆ update_failed()

static void update_failed ( int  code)
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.

Parameters
codeThe error code, gets written to config store and blinked.

Definition at line 164 of file bootloader.c.

◆ verify_signature()

static int verify_signature ( const char *  fname)
static

Verifies the signature of the file.

Parameters
fnameMBIN file to verify
Returns
BOOTLOADER_OK on success, else error code

Definition at line 501 of file bootloader.c.

Variable Documentation

◆ deflate_buffer

uint8_t deflate_buffer[MAX_SEGMENT_SIZE]
static

Temporary buffer for deflating segments.

Definition at line 105 of file bootloader.c.

◆ segment_buffer

uint8_t segment_buffer[MAX_SEGMENT_SIZE]
static

Temporary buffer for loading segments.

Definition at line 102 of file bootloader.c.