-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs: add nxboot documentation entry
This commit adds documentation entry for NuttX based bootloader nxboot. Signed-off-by: Michal Lenc <[email protected]>
- Loading branch information
1 parent
3818ce8
commit 9930a64
Showing
1 changed file
with
272 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,272 @@ | ||
=========================== | ||
``nxboot`` NuttX Bootloader | ||
=========================== | ||
|
||
NuttX Bootloader (nxboot) can be used to provide update and recovery | ||
capabilities for NuttX based devices. The bootloader implements an | ||
algorithm that uses three partitions/areas: primary, secondary and | ||
tertiary. Primary area is used to run the image and thus is usually | ||
located in program memory. Secondary and tertiary areas are used | ||
to store update image or recovery image and can be located on | ||
external flash memory for example. | ||
|
||
Please note that this bootloader is new and it is possible some of its | ||
characteristics might be changed/enhanced/fix as it is further used and | ||
tested. These might include slight changes in API and image format. | ||
|
||
Algorithm Description | ||
--------------------- | ||
|
||
The update is performed with a 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. | ||
|
||
Not confirmed image is reverted to recovery image if reboot occurs. | ||
|
||
The bootable image consists of a header :c:struct:`nxboot_img_header` | ||
containing magic, size of the image excluding the header, CRC32 of the | ||
image excluding the header and firmware version. The header is located | ||
prior to the image itself and has a configurable size | ||
``CONFIG_NXBOOT_HEADER_SIZE``. One erase page is also reserved at the | ||
end of the partition (the entire partition, not the image!). This page | ||
has two write blocks/pages with each one holding a flag. The first page | ||
from the end holds image confirmation flag, the second one holds the flag | ||
informing this image was already updated. These flags are written by the | ||
bootloader and are used to detect which partition is update/recovery | ||
and whether the image is confirmed or not. | ||
|
||
There are two variants of bootable image. The first is the image that is | ||
expected to be flashed directly into the primary area via physical programmer | ||
as STlink or JTAG. This image does not use CRC32 for validation and does | ||
not contain tail with the flags described above. It has an inverted | ||
magic value compared to the update image. This should not be used | ||
for OTA update, but only for the initial upload of the software to the | ||
device. | ||
|
||
The update image has a valid precalculated CRC32 and standard magic value. | ||
The image is expected to be uploaded to the board either via programmer | ||
or some protocol (Ethernet, CAN, etc.) to the external flash. The primary | ||
flash can be used as well, but this halts the program execution during write | ||
operations, so it is not recommended if external flash can be used. The | ||
uploaded image is detected by the bootloader during the next boot and update | ||
occurs. The program responsible for uploading the update image to the | ||
partition has to erase the last erase page in this partition to ensure | ||
all flags are unset. | ||
|
||
The application can use function :c:func:`nxboot_get_state` to determine | ||
what partition is update and recovery and thus where the update image | ||
should be stored. | ||
|
||
Hardware Requirements | ||
--------------------- | ||
|
||
As mentioned above, the bootlaoder utilizes three partitions with the | ||
first one typically located in program flash. | ||
|
||
The bootloader itself requires the minimal knowledge about characteristics | ||
of the underlying storage device. This is achieved by means of the ``BCH`` | ||
and ``FTL`` subsystems, which enable the bootloader to manage MTD partitions | ||
via character device drivers using standard POSIX filesystem operations | ||
(e.g. ``open()`` / ``close()`` / ``read()`` / ``write()``). | ||
|
||
It is currently required to access the partitions via mentioned ``BCH`` | ||
and ``FTL`` subsystems, but future enhancement could provide a direct access | ||
with ``MTD`` layer. | ||
|
||
Configuration | ||
------------- | ||
|
||
Following configuration options are available: | ||
|
||
- ``CONFIG_BOOT_NXBOOT``: Enables NuttX Bootloader build. | ||
- ``CONFIG_NXBOOT_PRIMARY_SLOT_PATH``: | ||
The path to the application firmware image primary slot character | ||
device driver. The image runs from this location. Default is ``dev/ota0``. | ||
- ``CONFIG_NXBOOT_SECONDARY_SLOT_PATH``: | ||
The path to the application firmware image primary slot character device | ||
driver. This is either update or recovery slot.. Default is ``dev/ota1``. | ||
- ``CONFIG_NXBOOT_TERTIARY_SLOT_PATH``: | ||
The path to the application firmware image primary slot character device | ||
driver. This is either update or recovery slot.. Default is ``dev/ota2``. | ||
- ``CONFIG_NXBOOT_HEADER_SIZE``: | ||
Size of the image header. Note that this size should be aligned with the | ||
program memory write page size! | ||
- ``CONFIG_NXBOOT_BOOTLOADER``: | ||
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. | ||
- ``CONFIG_NXBOOT_SWRESET_ONLY``: | ||
This option ensures the update/revert is performed only for software | ||
reset. This way the board can keep its image (even if not confirmed) | ||
during for example power shutdown and perform update/revert only if | ||
expected based on user/maintainer input. Following reset causes | ||
are considered as software resets. | ||
|
||
``BOARDIOC_RESETCAUSE_CPU_SOFT``: software reset | ||
|
||
``BOARDIOC_RESETCAUSE_CPU_RWDT``: watchdog error | ||
|
||
``BOARDIOC_RESETCAUSE_PIN``: reset button | ||
|
||
- ``NXBOOT_PREVENT_DOWNGRADE`` : | ||
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 implements preferences only for | ||
``MAJOR.MINOR.PATCH`` and ignores prerelease. | ||
|
||
Image Creation | ||
-------------- | ||
|
||
The image intended to be booted by nxboot bootlaoder must have prepended header | ||
to be recognized and worked with correctly. A Python script ``nximage.py`` | ||
located in ``apps/boot/nxboot/tools`` directory can be used to generate | ||
nxboot compatible image. | ||
|
||
.. code-block:: bash | ||
python3 apps/boot/nxboot/tools/nximage.py \ | ||
--version "VERSION" \ | ||
--header_size CONFIG_NXBOOT_HEADER_SIZE \ | ||
--primary \ | ||
nuttx.bin image.img | ||
It takes input parameters ``--version`` with your image's version and | ||
``--header_size`` with the configured size of the header. Option | ||
``--primary`` generates the primary. This option should be used only | ||
for image intended to be flashed directly to program memory (with | ||
flashing tool like STlink). It must not be set for image intended to be used | ||
as update image. The input file is a binary ``nuttx.bin``, output with added | ||
header is ``image.img``. | ||
|
||
Image version adheres to `Semantic Versioning 2.0.0 <https://semver.org/spec/v2.0.0.html>`__ | ||
without the usage of build metadata. The used format is | ||
MAJOR.MINOR:PATCH-prerelease. The image version is important for the update | ||
to occur as the bootloader automatically rejects update firmware that | ||
has the same version as the already running firmware. | ||
Configuration options: | ||
|
||
Public API | ||
---------- | ||
|
||
Enabling ``CONFIG_BOOT_NXBOOT`` option provides following NXboot API. | ||
|
||
.. code-block:: c | ||
#include <nxboot.h> | ||
.. c:struct:: nxboot_img_version | ||
.. code-block:: c | ||
#define NXBOOT_HEADER_PRERELEASE_MAXLEN 110 | ||
struct nxboot_img_version | ||
{ | ||
/* MAJOR version */ | ||
uint16_t major; | ||
/* MINOR version */ | ||
uint16_t minor; | ||
/* PATCH version */ | ||
uint16_t patch; | ||
/* Additional pre-release version */ | ||
char pre_release[NXBOOT_HEADER_PRERELEASE_MAXLEN]; | ||
}; | ||
.. c:struct:: nxboot_img_header | ||
.. code-block:: c | ||
#define NXBOOT_HEADER_MAGIC 0x534f584e | ||
#define NXBOOT_HEADER_MAGIC_INV 0xaca0abb1 | ||
struct nxboot_img_header | ||
{ | ||
/* Header magic */ | ||
uint32_t magic; | ||
/* Image size (excluding the header) */ | ||
uint32_t size; | ||
/* CRC32 of image (excluding the header) */ | ||
uint32_t crc32; | ||
/* Image version */ | ||
struct nxboot_img_version img_version; | ||
}; | ||
.. c:enum:: nxboot_update_type | ||
.. code-block:: c | ||
enum nxboot_update_type | ||
{ | ||
/* No action to do */ | ||
NXBOOT_UPDATE_TYPE_NONE = 0, | ||
/* Update will take place upon reboot */ | ||
NXBOOT_UPDATE_TYPE_UPDATE = 1, | ||
/* Revert will take place upon reboot */ | ||
NXBOOT_UPDATE_TYPE_REVERT = 2, | ||
}; | ||
.. c:struct:: nxboot_state | ||
.. code-block:: c | ||
#define NXBOOT_PRIMARY_SLOT_NUM 0 | ||
#define NXBOOT_SECONDARY_SLOT_NUM 1 | ||
#define NXBOOT_TERTIARY_SLOT_NUM 2 | ||
struct nxboot_state | ||
{ | ||
/* Number of update slot */ | ||
int update; | ||
/* Number of recovery slot */ | ||
int recovery; | ||
/* True if recovery image contains valid recovery */ | ||
bool recovery_valid; | ||
/* True if primary slot is confirmed */ | ||
bool primary_confirmed; | ||
/* True if update slot has a valid image */ | ||
enum nxboot_update_type next_boot; | ||
}; | ||
.. c:function:: int nxboot_get_state(struct nxboot_state *state) | ||
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. | ||
:param state: A pointer to ``struct nxboot_state`` structure. | ||
:return: 0 on success, -1 and sets errno on failure. | ||
.. c:function:: int nxboot_get_confirm(void) | ||
Confirms the image currently located in primary partition and marks | ||
its copy in update partition as a recovery. | ||
:return: 1 means confirmed, 0 not confirmed, -1 and sets errno on failure. | ||
.. c:function:: int nxboot_confirm(void) | ||
Confirms the image currently located in primary partition and marks | ||
its copy in update partition as a recovery. | ||
:return: 0 on success, -1 and sets errno on failure. | ||
.. c:function:: int nxboot_perform_update(bool check_only) | ||
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. | ||
:param check_only: Only repairs corrupted update. | ||
:return: 0 on success, -1 and sets errno on failure. |