Skip to content

Commit

Permalink
boot/mcuboot: Add support for MCUboot bootloader
Browse files Browse the repository at this point in the history
Signed-off-by: Gustavo Henrique Nihei <[email protected]>
  • Loading branch information
gustavonihei authored and acassis committed Aug 20, 2021
1 parent e6b767f commit 794cfd0
Show file tree
Hide file tree
Showing 10 changed files with 684 additions and 0 deletions.
1 change: 1 addition & 0 deletions boot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/Kconfig
21 changes: 21 additions & 0 deletions boot/Make.defs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
############################################################################
# apps/boot/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.
#
############################################################################

include $(wildcard $(APPDIR)/boot/*/Make.defs)
23 changes: 23 additions & 0 deletions boot/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
############################################################################
# apps/boot/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.
#
############################################################################

MENUDESC = "Bootloader Utilities"

include $(APPDIR)/Directory.mk
2 changes: 2 additions & 0 deletions boot/mcuboot/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/mcuboot
/*.tar.gz
122 changes: 122 additions & 0 deletions boot/mcuboot/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#

menuconfig BOOT_MCUBOOT
bool "MCUboot"
default n
select BCH
---help---
Enable support for the MCUboot bootloader.

if BOOT_MCUBOOT

config MCUBOOT_VERSION
string "MCUboot version"
default "01184bd0361c4128c6382aa9c640b02e7f1422f6"

config MCUBOOT_ENABLE_LOGGING
bool "Enable MCUboot logging"
default n
---help---
Enable MCUboot's logging infrastructure.

config MCUBOOT_BOOTLOADER
bool "MCUboot bootloader application"
default n
select BOARDCTL
select BOARDCTL_BOOT_IMAGE
---help---
MCUboot bootloader application.

config MCUBOOT_UPDATE_AGENT_EXAMPLE
bool "MCUboot update agent example"
default n
depends on NET_TCP
---help---
Example application that implements an update agent that downloads
an application firmware image from a given URL and saves it to the
secondary slot as a pending update.

if MCUBOOT_UPDATE_AGENT_EXAMPLE

config MCUBOOT_UPDATE_AGENT_EXAMPLE_UPDATE_URL
string "URL for update image"
default ""

config MCUBOOT_UPDATE_AGENT_EXAMPLE_DL_BUFFER_SIZE
int "Download buffer size in bytes"
default 512

config MCUBOOT_UPDATE_AGENT_EXAMPLE_DL_VERIFY_MD5
bool "Calculate MD5 of update image"
default n
depends on CODECS_HASH_MD5

config MCUBOOT_UPDATE_AGENT_EXAMPLE_DL_MD5_HASH
string "Expected MD5 sum of update image"
default ""
depends on MCUBOOT_UPDATE_AGENT_EXAMPLE_DL_VERIFY_MD5

endif # MCUBOOT_UPDATE_AGENT_EXAMPLE

config MCUBOOT_SLOT_CONFIRM_EXAMPLE
tristate "MCUboot slot confirm example"
default n
---help---
Example application for confirming a newly installed application
application firmware image using MCUboot public APIs.
This application should be used as the OTA update package of the
MCUBOOT_UPDATE_AGENT_EXAMPLE example.

config MCUBOOT_WATCHDOG
bool "Watchdog feeding support"
default n
depends on WATCHDOG
---help---
This config must be selected in case the Watchdog is enabled while
performing a swap upgrade and the time it takes for a swapping is long
enough to cause an unwanted reset.

config MCUBOOT_WATCHDOG_DEVPATH
string "Watchdog device path"
default "/dev/watchdog0"
depends on MCUBOOT_WATCHDOG
---help---
The path to the watchdog device.
Default: /dev/watchdog0

config MCUBOOT_PRIMARY_SLOT_PATH
string "Application firmware image primary slot path"
default "/dev/ota0"
---help---
The path to the application firmware image primary slot character
device driver.
Default: /dev/ota0

config MCUBOOT_SECONDARY_SLOT_PATH
string "Application firmware image secondary slot path"
default "/dev/ota1"
---help---
The path to the application firmware image secondary slot character
device driver.
Default: /dev/ota1

config MCUBOOT_SCRATCH_PATH
string "Scratch partition path"
default "/dev/otascratch"
---help---
The path to the scratch partition character device driver.
Default: /dev/otascratch

config MCUBOOT_DEFAULT_FLASH_ERASE_STATE
hex "Default flash erase state"
default 0xff
---help---
MCUboot will attempt to retrieve this value from the underlying MTD
driver.
In case of failure, the value from this config will be used as a
fallback.

endif # BOOT_MCUBOOT
34 changes: 34 additions & 0 deletions boot/mcuboot/Make.defs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
############################################################################
# apps/boot/mcuboot/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.
#
############################################################################

ifeq ($(CONFIG_BOOT_MCUBOOT),y)
CONFIGURED_APPS += $(APPDIR)/boot/mcuboot

# It allows import of NuttX implementation headers for MCUboot interfaces.

CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/boot/mcuboot/mcuboot/boot/nuttx/include}
CXXFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/boot/mcuboot/mcuboot/boot/nuttx/include}

# It allows import of MCUboot's bootutil library headers.

CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/boot/mcuboot/mcuboot/boot/bootutil/include}
CXXFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)/boot/mcuboot/mcuboot/boot/bootutil/include}

endif
92 changes: 92 additions & 0 deletions boot/mcuboot/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
############################################################################
# apps/boot/mcuboot/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

MCUBOOT_VERSION := $(patsubst "%",%,$(CONFIG_MCUBOOT_VERSION))
MCUBOOT_TARBALL = $(MCUBOOT_VERSION).tar.gz
MCUBOOT_UNPACK = mcuboot
MCUBOOT_SRCDIR = $(MCUBOOT_UNPACK)$(DELIM)boot$(DELIM)bootutil$(DELIM)src

DEPPATH += --dep-path $(MCUBOOT_UNPACK)$(DELIM)src
DEPPATH += --dep-path $(MCUBOOT_SRCDIR)
VPATH += :$(MCUBOOT_UNPACK)$(DELIM)src
VPATH += :$(MCUBOOT_SRCDIR)

ifneq ($(CONFIG_MCUBOOT_UPDATE_AGENT_EXAMPLE),)
MAINSRC = mcuboot_agent_main.c

PROGNAME = mcuboot_agent
PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
else ifneq ($(CONFIG_MCUBOOT_SLOT_CONFIRM_EXAMPLE),)
MAINSRC = mcuboot_confirm_main.c

PROGNAME = mcuboot_confirm
PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
else ifneq ($(CONFIG_MCUBOOT_BOOTLOADER),)
MAINSRC = mcuboot/boot/nuttx/main.c

PROGNAME = mcuboot_loader
PRIORITY = SCHED_PRIORITY_DEFAULT
STACKSIZE = $(CONFIG_DEFAULT_TASK_STACKSIZE)
endif

CSRCS := mcuboot/boot/bootutil/src/boot_record.c \
mcuboot/boot/bootutil/src/bootutil_misc.c \
mcuboot/boot/bootutil/src/bootutil_public.c \
mcuboot/boot/bootutil/src/caps.c \
mcuboot/boot/bootutil/src/encrypted.c \
mcuboot/boot/bootutil/src/fault_injection_hardening.c \
mcuboot/boot/bootutil/src/fault_injection_hardening_delay_rng_mbedtls.c \
mcuboot/boot/bootutil/src/image_ec.c \
mcuboot/boot/bootutil/src/image_ec256.c \
mcuboot/boot/bootutil/src/image_ed25519.c \
mcuboot/boot/bootutil/src/image_rsa.c \
mcuboot/boot/bootutil/src/image_validate.c \
mcuboot/boot/bootutil/src/loader.c \
mcuboot/boot/bootutil/src/swap_misc.c \
mcuboot/boot/bootutil/src/swap_move.c \
mcuboot/boot/bootutil/src/swap_scratch.c \
mcuboot/boot/bootutil/src/tlv.c \
mcuboot/boot/nuttx/src/flash_map_backend/flash_map_backend.c

ifneq ($(CONFIG_MCUBOOT_WATCHDOG),)
CSRCS += mcuboot/boot/nuttx/src/watchdog/watchdog.c
endif

$(MCUBOOT_TARBALL):
$(Q) echo "Downloading MCUboot-$(MCUBOOT_VERSION)"
$(Q) curl -O -L https://github.com/mcu-tools/mcuboot/archive/$(MCUBOOT_TARBALL)

$(MCUBOOT_UNPACK): $(MCUBOOT_TARBALL)
$(Q) echo "Unpacking: $(MCUBOOT_TARBALL) -> $(MCUBOOT_UNPACK)"
$(Q) tar zxf $(MCUBOOT_TARBALL)
$(Q) mv mcuboot-$(MCUBOOT_VERSION) $(MCUBOOT_UNPACK)
$(Q) touch $(MCUBOOT_UNPACK)

context:: $(MCUBOOT_UNPACK)

distclean::
$(call DELFILE, $(MCUBOOT_TARBALL))
$(call DELDIR, $(MCUBOOT_UNPACK))

include $(APPDIR)/Application.mk
52 changes: 52 additions & 0 deletions boot/mcuboot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Boot / `mcuboot` MCUboot

## Description

The NuttX port of MCUboot secure boot library expects that the platform provides a Flash storage with the following partitions:
- `CONFIG_MCUBOOT_PRIMARY_SLOT_PATH`: MTD partition for the application firmware image PRIMARY slot;
- `CONFIG_MCUBOOT_SECONDARY_SLOT_PATH`: MTD partition for the application firmware image SECONDARY slot;
- `CONFIG_MCUBOOT_SCRATCH_PATH`: MTD partition for the Scratch area;

Also, these are optional features that may be enabled:

- `CONFIG_MCUBOOT_WATCHDOG`: If `CONFIG_WATCHDOG` is enabled, MCUboot shall reset the watchdog timer indicated by `CONFIG_MCUBOOT_WATCHDOG_DEVPATH` to the current timeout value, preventing any imminent watchdog timeouts.

The porting layer of MCUboot library consists of the following interfaces:
- `<flash_map_backend/flash_map_backend.h>`, for enabling MCUboot to manage the application firmware image slots in the device storage.
- `<mcuboot_config/mcuboot_config.h>`, for configuration of MCUboot's features.
- `<mcuboot_config/mcuboot_logging.h>`, for providing logging capabilities.
- `<os/os_malloc.h>`, for providing MCUboot access to the OS memory management interfaces.
- `<sysflash/sysflash.h>`, for configuration of the system's flash area organization.

The NuttX port of MCUboot is implemented at application-level and requires minimal knowledge about characteristics of the underlying storage device. This is achieved by means of the `BCH` and `FTL` subsystems, which enable MCUboot to manage MTD partitions via character device drivers using standard POSIX filesystem operations (e.g. `open()` / `close()` / `read()` / `write()`).

## Creating MCUboot-compatible application firmware images

One common use case for MCUboot is to integrate it to a firmware update agent, which is an important component of a secure firmware update subsystem. Through MCUboot APIs an application is able to install a newly received application firmware image and, once this application firmware image is assured to be valid, the application may confirm it as a stable image. In case that application firmware image is deemed bogus, MCUboot provides an API for invalidating that update, which will induce a rollback procedure to the most recent stable application firmware image.

The `CONFIG_MCUBOOT_UPDATE_AGENT_EXAMPLE` example demonstrates this workflow by downloading an application firmware image from a webserver, installing it and triggering the firmware update process for the next boot after a system reset. There is also the `CONFIG_MCUBOOT_SLOT_CONFIRM_EXAMPLE`, which is a fairly simple example that just calls an MCUboot API for confirming the executing application firmware image as stable.

## Using MCUboot on NuttX as a secure boot solution

NuttX port for MCUboot also enables the creation of a secure bootloader application requiring minimal platform-specific implementation. The logical implementation for the secure boot is performed at application-level by the MCUboot library. Once MCUboot validates the application firmware image, it delegates the loading and execution of the application firmware image to a platform-specific routine, which is accessed via `boardctl(BOARDIOC_BOOT_IMAGE)` call. Each platform must then provide an implementation for the `board_boot_image()` for executing the required actions in order to boot a new application firmware image (e.g. deinitialize peripherals, load the Program Counter register with the application firmware image entry point address).

The MCUboot bootloader application may be enabled by selecting the `CONFIG_MCUBOOT_BOOTLOADER` option.

## Assumptions

### IOCTL MTD commands

The implementation of `<flash_map_backend/flash_map_backend.h>` expects that the MTD driver for a given image partition handles the following `ioctl` commands:
- `MTDIOC_GEOMETRY`, for retrieving information about the geometry of the MTD, required for the configuration of the size of each flash area.
- `MTDIOC_ERASESTATE`, for retrieving the byte value of an erased cell of the MTD, required for the implementation of `flash_area_erased_val()` interface.

### Write access alignment

Through `flash_area_align()` interface MCUboot expects that the implementation provides the shortest data length that may be written via `flash_area_write()` interface. The NuttX implementation passes through the `BCH` and `FTL` layers, which appropriately handle the write alignment restrictions of the underlying MTD. So The NuttX implementation of `flash_area_align()` is able to return a fixed value of 1 byte, even if the MTD does not support byte operations.

## Limitations

### `<flash_map_backend/flash_map_backend.h>` functions are not multitasking-safe

MCUboot's documentation imposes no restrictions regarding the usage of its public interfaces, which doesn't mean they are thread-safe.
But, regarding NuttX implementation of the `<flash_map_backend/flash_map_backend.h>`, it is safe to state that they are **not** multitasking-safe. NuttX implementation manages the MTD partitions via character device drivers. As file-descriptors cannot be shared between different tasks, if one task calls `flash_area_open` and another task calls `flash_area_<read/write/close>` passing the same `struct flash_area` instance, it will result in failure.
Loading

0 comments on commit 794cfd0

Please sign in to comment.