-
Notifications
You must be signed in to change notification settings - Fork 541
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
boot: add NuttX bootloader with update and recovery support
This commit adds NuttX based bootloader with the support for image update and recovery if not confirmed. The algorithm utilizes three flash partitions: primary (image runs from this area), secondary and tertiary. Secondary and tertiary areas are used for update upload and recovery. The update is performed by simple copy from update area to primary area with recovery being created in recovery area if not already present. Once image is confirmed by the user, the image in update area is confirmed as well, update area becomes recovery area and vice versa. This means the recovery is always present (except for the first update) and subsequent updates just copy image from update to primary. This makes the update significantly faster and more considerable to flash wear while keeping the recovery/revert possibility. A header (aligned to flash's erase size) must be added to the beginning of the image. Python script nximage.py can be used to prepend this header to built binary. The algorithm also uses one erase page at the end of a partition (partition, not image!) to store flags used to indicate image confirm status and to detect update/recovery partitions. Any program uploading update image to the update partition has to erase this page for the boot to work correctly! The algorithm implementation is based on a patch initially developed for MCUboot project but rejected by the project's maintainers mcu-tools/mcuboot#1902 Signed-off-by: Michal Lenc <[email protected]>
- Loading branch information
1 parent
34ca696
commit 250a0ba
Showing
11 changed files
with
1,798 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# ############################################################################## | ||
# apps/boot/nxboot/CMakeLists.txt | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one or more contributor | ||
# license agreements. See the NOTICE file distributed with this work for | ||
# additional information regarding copyright ownership. The ASF licenses this | ||
# file to you under the Apache License, Version 2.0 (the "License"); you may not | ||
# use this file except in compliance with the License. You may obtain a copy of | ||
# the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations under | ||
# the License. | ||
# | ||
# ############################################################################## | ||
|
||
if(CONFIG_BOOT_NXBOOT) | ||
nuttx_add_library(nxboot) | ||
set(SRCS | ||
loader/boot.c | ||
loader/flash.c) | ||
|
||
if(BOOT_NXBOOT) | ||
nuttx_add_application( | ||
NAME | ||
nxboot_loader | ||
SRCS | ||
nxboot_main.c | ||
INCLUDE_DIRECTORIES | ||
include) | ||
endif() | ||
|
||
target_include_directories(nxboot PUBLIC include) | ||
target_sources(nxboot PRIVATE ${SRCS}) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# | ||
# For a description of the syntax of this configuration file, | ||
# see the file kconfig-language.txt in the NuttX tools repository. | ||
# | ||
|
||
menuconfig BOOT_NXBOOT | ||
bool "NuttX bootloader" | ||
default n | ||
select BCH | ||
---help--- | ||
Enable support for the minimal NuttX based bootloader. | ||
|
||
if BOOT_NXBOOT | ||
|
||
config NXBOOT_PRIMARY_SLOT_PATH | ||
string "Application firmware primary image slot path" | ||
default "/dev/ota0" | ||
---help--- | ||
The path to the application firmware image primary slot character | ||
device driver. The image runs from this location. | ||
Default: /dev/ota0 | ||
|
||
config NXBOOT_SECONDARY_SLOT_PATH | ||
string "Application firmware secondary image slot path" | ||
default "/dev/ota1" | ||
---help--- | ||
The path to the application firmware image primary slot character | ||
device driver. This is either update or recovery slot. | ||
Default: /dev/ota1 | ||
|
||
config NXBOOT_TERTIARY_SLOT_PATH | ||
string "Application firmware tertiary image slot path" | ||
default "/dev/ota2" | ||
---help--- | ||
The path to the application firmware image primary slot character | ||
device driver. This is either update or recovery slot. | ||
Default: /dev/ota2 | ||
|
||
config NXBOOT_HEADER_SIZE | ||
hex "Application firmware image header size" | ||
default 0x200 | ||
---help--- | ||
Note that this size should be aligned with the program memory erase | ||
page size! | ||
|
||
config NXBOOT_BOOTLOADER | ||
bool "Build nxboot bootloader application" | ||
default n | ||
select BOARDCTL | ||
select BOARDCTL_BOOT_IMAGE | ||
---help--- | ||
This option builds and links a bootloader application. This application | ||
should be an entry function for NuttX. It checks for possible update/ | ||
revert operation, performs it and boot the correct image. | ||
|
||
if NXBOOT_BOOTLOADER | ||
|
||
config NXBOOT_SWRESET_ONLY | ||
bool "Perform update/revert only on SW reset" | ||
default n | ||
select BOARDCTL_RESET_CAUSE | ||
---help--- | ||
This option ensures the update/revert is performed only for following | ||
reset causes: | ||
BOARDIOC_RESETCAUSE_CPU_SOFT: software reset | ||
BOARDIOC_RESETCAUSE_CPU_RWDT: watchdog error | ||
BOARDIOC_RESETCAUSE_PIN: reset button | ||
|
||
This way the board can keep its image (even if not confirmed) during | ||
for example power shutdown and perform update/revent only if expected | ||
based on user/maintainer input. | ||
|
||
config NXBOOT_PREVENT_DOWNGRADE | ||
bool "Perform update only for newer version" | ||
default n | ||
---help--- | ||
NXboot uses Semantic Version 2.0.0 (without build metadata). By default | ||
the update is performed for every version that doesn't match the | ||
currently running one. If NXBOOT_PREVENT_DOWNGRADE selected, update is | ||
performed only for newer versions (according to Semantic Version | ||
preference rules). | ||
|
||
WARNING: NXboot currently implementes preferences only for | ||
MAJOR.MINOR.PATCH and ignores prerelease. | ||
|
||
endif # NXBOOT_BOOTLOADER | ||
|
||
endif # BOOT_NXBOOT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
############################################################################ | ||
# apps/boot/nxboot/Make.defs | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one or more | ||
# contributor license agreements. See the NOTICE file distributed with | ||
# this work for additional information regarding copyright ownership. The | ||
# ASF licenses this file to you under the Apache License, Version 2.0 (the | ||
# "License"); you may not use this file except in compliance with the | ||
# License. You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
# | ||
############################################################################ | ||
|
||
ifneq ($(CONFIG_BOOT_NXBOOT),) | ||
CONFIGURED_APPS += $(APPDIR)/boot/nxboot | ||
|
||
CFLAGS += ${INCDIR_PREFIX}$(APPDIR)/boot/nxboot/include | ||
|
||
endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
############################################################################ | ||
# apps/boot/nxboot/Makefile | ||
# | ||
# Licensed to the Apache Software Foundation (ASF) under one or more | ||
# contributor license agreements. See the NOTICE file distributed with | ||
# this work for additional information regarding copyright ownership. The | ||
# ASF licenses this file to you under the Apache License, Version 2.0 (the | ||
# "License"); you may not use this file except in compliance with the | ||
# License. You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
# License for the specific language governing permissions and limitations | ||
# under the License. | ||
# | ||
############################################################################ | ||
|
||
include $(APPDIR)/Make.defs | ||
|
||
ifneq ($(CONFIG_NXBOOT_BOOTLOADER),) | ||
PROGNAME = nxboot_loader | ||
PRIORITY = SCHED_PRIORITY_DEFAULT | ||
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE) | ||
|
||
MAINSRC = nxboot_main.c | ||
endif | ||
|
||
CSRCS := loader/boot.c \ | ||
loader/flash.c | ||
|
||
include $(APPDIR)/Application.mk |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
/**************************************************************************** | ||
* apps/boot/nxboot/include/nxboot.h | ||
* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. The | ||
* ASF licenses this file to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance with the | ||
* License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
****************************************************************************/ | ||
|
||
#ifndef __BOOT_NXBOOT_INCLUDE_NXBOOT_H | ||
#define __BOOT_NXBOOT_INCLUDE_NXBOOT_H | ||
|
||
/**************************************************************************** | ||
* Included Files | ||
****************************************************************************/ | ||
|
||
#include <nuttx/config.h> | ||
#include <assert.h> | ||
#include <stdbool.h> | ||
|
||
/**************************************************************************** | ||
* Pre-processor Definitions | ||
****************************************************************************/ | ||
|
||
#define NXBOOT_PRIMARY_SLOT_NUM (0) | ||
#define NXBOOT_SECONDARY_SLOT_NUM (1) | ||
#define NXBOOT_TERTIARY_SLOT_NUM (2) | ||
|
||
/* Offsets to write pages containing confirmed and updated flags. These | ||
* pages are located at the end of the partition, therefore index 0 means | ||
* the first page from the end. | ||
*/ | ||
|
||
#define NXBOOT_CONFIRMED_PAGE_INDEX (0) | ||
#define NXBOOT_UPDATED_PAGE_INDEX (1) | ||
|
||
#define NXBOOT_HEADER_MAGIC 0x534f584e /* NXOS. */ | ||
#define NXBOOT_HEADER_MAGIC_INV 0xaca0abb1 /* NXOS inverted. This is used | ||
* for images uploaded directly | ||
* to the primary flash with | ||
* the debugger. These images | ||
* does not have precalculated | ||
* CRC and flags at the | ||
* end of the partition, but | ||
* are considered to be valid. | ||
*/ | ||
|
||
#define NXBOOT_HEADER_PRERELEASE_MAXLEN 110 | ||
|
||
/**************************************************************************** | ||
* Public Types | ||
****************************************************************************/ | ||
|
||
enum nxboot_update_type | ||
{ | ||
NXBOOT_UPDATE_TYPE_NONE = 0, /* No action to do */ | ||
NXBOOT_UPDATE_TYPE_UPDATE = 1, /* Update will take place upon reboot */ | ||
NXBOOT_UPDATE_TYPE_REVERT = 2, /* Revert will take place upon reboot */ | ||
}; | ||
|
||
/* Versioning is according to Semantic Versioning 2.0.0 | ||
* refer to (https://semver.org/spec/v2.0.0.html) | ||
*/ | ||
|
||
struct nxboot_img_version | ||
{ | ||
uint16_t major; /* MAJOR version */ | ||
uint16_t minor; /* MINOR version */ | ||
uint16_t patch; /* PATCH version */ | ||
|
||
char pre_release[NXBOOT_HEADER_PRERELEASE_MAXLEN]; /* Additional pre-release version */ | ||
}; | ||
|
||
struct nxboot_img_header | ||
{ | ||
uint32_t magic; /* Header magic */ | ||
uint32_t size; /* Image size (excluding the header) */ | ||
uint32_t crc; /* CRC32 of image (excluding the header). */ | ||
|
||
struct nxboot_img_version img_version; /* Image version */ | ||
}; | ||
static_assert(CONFIG_NXBOOT_HEADER_SIZE > sizeof(struct nxboot_img_header), | ||
"CONFIG_NXBOOT_HEADER_SIZE has to be larger than" | ||
"sizeof(struct nxboot_img_header)"); | ||
|
||
struct nxboot_state | ||
{ | ||
int update; /* Number of update slot */ | ||
int recovery; /* Number of recovery slot */ | ||
bool recovery_valid; /* True if recovery image contains valid recovery */ | ||
bool primary_confirmed; /* True if primary slot is confirmed */ | ||
enum nxboot_update_type next_boot; /* True if update slot has a valid image */ | ||
}; | ||
|
||
/**************************************************************************** | ||
* Public Function Prototypes | ||
****************************************************************************/ | ||
|
||
/**************************************************************************** | ||
* Name: nxboot_get_state | ||
* | ||
* Description: | ||
* Gets the current bootloader state and stores it in the nxboot_state | ||
* structure passed as an argument. This function may be used to determine | ||
* which slot is update slot and where should application save incoming | ||
* firmware. | ||
* | ||
* Input parameters: | ||
* state: The pointer to nxboot_state structure. The state is stored here. | ||
* | ||
* Returned Value: | ||
* 0 on success, -1 and sets errno on failure. | ||
* | ||
****************************************************************************/ | ||
|
||
int nxboot_get_state(struct nxboot_state *state); | ||
|
||
/**************************************************************************** | ||
* Name: nxboot_get_confirm | ||
* | ||
* Description: | ||
* This function can be used to determine whether primary image is | ||
* confirmed or not. This provides more direct access to confirm | ||
* state compared to nxboot_get_state function that returns the full | ||
* state of the bootloader. | ||
* | ||
* Returned Value: | ||
* 1 means confirmed, 0 not confirmed, -1 and sets errno on failure. | ||
* | ||
****************************************************************************/ | ||
|
||
int nxboot_get_confirm(void); | ||
|
||
/**************************************************************************** | ||
* Name: nxboot_confirm | ||
* | ||
* Description: | ||
* Confirms the image currently located in primary partition and marks | ||
* its copy in update partition as a recovery. | ||
* | ||
* Returned Value: | ||
* 0 on success, -1 and sets errno on failure. | ||
* | ||
****************************************************************************/ | ||
|
||
int nxboot_confirm(void); | ||
|
||
/**************************************************************************** | ||
* Name: nxboot_perform_swap | ||
* | ||
* Description: | ||
* Checks for the possible firmware update and performs it by copying | ||
* update image to primary slot or recovery image to primary slot in case | ||
* of the revert. In any situation, this function ends with the valid | ||
* image in primary slot. | ||
* | ||
* This is an entry point function that should be called from the | ||
* bootloader application. | ||
* | ||
* Input parameters: | ||
* check_only: Only repairs corrupted update, but do not start another one | ||
* | ||
* Returned Value: | ||
* 0 on success, -1 and sets errno on failure. | ||
* | ||
****************************************************************************/ | ||
|
||
int nxboot_perform_update(bool check_only); | ||
|
||
#endif /* __BOOT_NXBOOT_INCLUDE_NXBOOT_H */ |
Oops, something went wrong.