1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

riotboot: add riot-based minimal bootloader

riotboot is introduced here and makes use of riotboot_hdr,
which indentifies the images encapsulated as slots.
The slot size and offset is configurable, which makes
slots extendable if needed, e.g. 2 or more slots can be
transparently added.

Co-authored-by: Kaspar Schleiser <kaspar@schleiser.de>
Co-authored-by: Gaëtan Harter <gaetan.harter@fu-berlin.de>
This commit is contained in:
Francisco Acosta 2018-09-25 01:15:04 +02:00 committed by Kaspar Schleiser
parent a638f31bce
commit 281d8084bf
5 changed files with 273 additions and 0 deletions

View File

@ -434,6 +434,11 @@ else
_LINK = $(if $(CPPMIX),$(LINKXX),$(LINK)) $(UNDEF) $(LINKFLAGPREFIX)--start-group $(BASELIBS) -lm $(LINKFLAGPREFIX)--end-group $(LINKFLAGS) $(LINKFLAGPREFIX)-Map=$(BINDIR)/$(APPLICATION).map
endif # BUILDOSXNATIVE
# include bootloaders support. When trying to overwrite one variable
# like HEXFILE, the value will already have been evaluated when declaring
# the link target. Therefore, it must be placed before `link`.
include $(RIOTMAKE)/boot/riotboot.mk
ifeq ($(BUILD_IN_DOCKER),1)
link: ..in-docker-container
else

View File

@ -0,0 +1,25 @@
# Default RIOT bootloader
APPLICATION = riotboot
# Default testing board
BOARD ?= samr21-xpro
# Select the boards with riotboot feature
FEATURES_REQUIRED += riotboot
# Disable unused modules
CFLAGS += -DNDEBUG -DLOG_LEVEL=LOG_NONE
DISABLE_MODULE += auto_init
# Include riotboot flash partition functionality
USEMODULE += riotboot_slot
# RIOT codebase
RIOTBASE ?= $(CURDIR)/../../
include $(RIOTBASE)/Makefile.include
# limit riotboot bootloader size
# TODO: Manage to set this variable for boards which already embed a
# bootloader, currently it will be overwritten
ROM_LEN := $(RIOTBOOT_LEN)

View File

@ -0,0 +1,75 @@
# Overview
This folder contains a simple bootloader called "riotboot".
A header with metadata of length `RIOTBOOT_HDR_LEN` precedes
the RIOT firmware. The header contains "RIOT" as a magic
number to recognise a RIOT firmware image, a checksum, and
the version of the RIOT firmware `APP_VER`.
This bootloader verifies the checksum of the header which is located
at an offset (`ROM_OFFSET`) with respect to the `ROM_START_ADDR`
defined by the CPU, just after the space allocated for riotboot.
riotboot consists of:
- This application which serves as minimal bootloader,
- the module "riotboot_hdr" used to recognise RIOT firmware which riotboot
can boot,
- the module "riotboot_slot" used to manage the partitions (slots) with a
RIOT header attached to them,
- a tool in dist/tools/riotboot_gen_hdr for header generation,
- several make targets to glue everything together.
## Concept
`riotboot` expects the flash to be formatted in slots: at CPU_FLASH_BASE
address resides the bootloader, which is followed by a slot 0 with a
RIOT firmware.
A RIOT firmware in a single slot is composed by:
```
|------------------------------- FLASH -------------------------------------|
|----- RIOTBOOT_LEN ----|----------- RIOTBOOT_SLOT_SIZE (slot 0) -----------|
|----- RIOTBOOT_HDR_LEN ------|
---------------------------------------------------------------------------
| riotboot | riotboot_hdr_t + filler (0) | RIOT firmware |
---------------------------------------------------------------------------
```
Please note that `RIOTBOOT_HDR_LEN` depends on the architecture of the
MCU, since it needs to be aligned to 256B. This is fixed regardless of
`sizeof(riotboot_hdr_t)`
The bootloader will, on reset, verify the checksum of the first slot header,
then boot it. If the slot doesn't have a valid checksum, no image will be
booted and the bootloader will enter `while(1);` endless loop.
# Requirements
A board capable to use riotboot must meet the following requirements:
- Embed a Cortex-M0+/3/4/7 processor
- Provide the variables `ROM_START_ADDR` and `ROM_LEN`
- Use cpu/cortexm_common/ldscripts/cortexm.ld ld script
- Pass the cortexm_common_ldscript test in tests/
- Being able to execute startup code at least twice (`board_init()`)
- Declare `FEATURES_PROVIDED += riotboot` to pull the rigth dependencies
- Being able to flash binary files, if integration with the build
system is required for flashing
The above requirements are usually met if the board succeeds to execute
the riotboot test in tests/.
# Usage
Just compile your application using the target `riotboot`. The header
is generated automatically according to your `APP_VER`, which can be
optionally set (0 by default) in your makefile.
## Flashing
The image can be flashed using `riotboot/flash` which also flashes
the bootloader.
e.g. `BOARD=samr21-xpro FEATURES_REQUIRED+=riotboot APP_VER=$(date +%s) make -C examples/hello-world riotboot/flash`
The command compiles both the hello-world example and riotboot,
generates the header and attaches it at the beginning of the example
binary.
A comprehensive test is available at tests/riotboot.

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
* Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup bootloaders RIOT compatible bootloaders
* @ingroup bootloaders
* @{
*
* @file
* @brief Minimal riot-based bootloader
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Francisco Acosta <francisco.acosta@inria.fr>
*
* @}
*/
#include "cpu.h"
#include "panic.h"
#include "riotboot/slot.h"
void kernel_init(void)
{
/* bootloader boots only slot 0 if it is valid */
unsigned slot = 0;
if (riotboot_slot_validate(slot) == 0) {
riotboot_slot_jump(slot);
}
/* serious trouble! */
while (1) {}
}
NORETURN void core_panic(core_panic_t crash_code, const char *message)
{
(void)crash_code;
(void)message;
while (1) {}
}

122
makefiles/boot/riotboot.mk Normal file
View File

@ -0,0 +1,122 @@
ifneq (,$(filter riotboot,$(FEATURES_USED)))
.PHONY: riotboot/flash riotboot/flash-bootloader riotboot/flash-slot0 riotboot/bootloader/%
RIOTBOOT_DIR = $(RIOTBASE)/bootloaders/riotboot
RIOTBOOT ?= $(RIOTBOOT_DIR)/bin/$(BOARD)/riotboot.elf
CFLAGS += -I$(BINDIR)/riotbuild
HEADER_TOOL_DIR = $(RIOTBASE)/dist/tools/riotboot_gen_hdr
HEADER_TOOL ?= $(HEADER_TOOL_DIR)/bin/genhdr
BINDIR_APP = $(BINDIR)/$(APPLICATION)
# Indicate the reserved space for a header, 256B by default
# Notice that it must be 256B aligned. This is restricted by
# the Cortex-M0+/3/4/7 architecture
RIOTBOOT_HDR_LEN ?= 0x100
# Export variables for 'riotboot_slot'
export SLOT0_LEN
# By default, slot 0 is found just after RIOTBOOT_LEN. It might
# be overridden to add more offset as needed.
export SLOT0_OFFSET ?= $(RIOTBOOT_LEN)
# Mandatory APP_VER, set to 0 by default
APP_VER ?= 0
# Final target for slot 0 with riot_hdr
SLOT0_RIOT_BIN = $(BINDIR_APP)-slot0.riot.bin
# For slot generation only link is needed
$(BINDIR_APP)-%.elf: link
$(Q)$(_LINK) -o $@
# Slot 0 firmware offset, after header
SLOT0_IMAGE_OFFSET := $$(($(RIOTBOOT_LEN) + $(RIOTBOOT_HDR_LEN)))
# Link slots ELF *after* riot_hdr and limit the ROM to the slots length
$(BINDIR_APP)-slot0.elf: FW_ROM_LEN=$$((SLOT0_LEN - $(RIOTBOOT_HDR_LEN)))
$(BINDIR_APP)-slot0.elf: ROM_OFFSET=$(SLOT0_IMAGE_OFFSET)
# Create binary target with RIOT header
$(SLOT0_RIOT_BIN): %.riot.bin: %.hdr %.bin
@echo "creating $@..."
$(Q)cat $^ > $@
# Compile header tool if it doesn't exist, force its compilation in case
# some files changed
$(HEADER_TOOL): FORCE
@echo "compiling $@..."
$(Q)/usr/bin/env -i \
QUIET=$(QUIET) \
PATH=$(PATH) \
$(MAKE) --no-print-directory -C $(HEADER_TOOL_DIR) all
# Generate RIOT header and keep the original binary file
# It must be always regenerated in case of any changes, so FORCE
.PRECIOUS: %.bin
%.hdr: $(HEADER_TOOL) %.bin FORCE
$(Q)$(HEADER_TOOL) generate $< $(APP_VER) $$(($(ROM_START_ADDR)+$(OFFSET))) $(RIOTBOOT_HDR_LEN) - > $@
$(BINDIR_APP)-slot0.hdr: OFFSET=$(SLOT0_IMAGE_OFFSET)
# Generic target to create a binary file from the image with header
riotboot: $(SLOT0_RIOT_BIN)
# riotboot bootloader compile target
riotboot/flash-bootloader: riotboot/bootloader/flash
riotboot/bootloader/%:
$(Q)/usr/bin/env -i \
QUIET=$(QUIET)\
PATH=$(PATH) BOARD=$(BOARD) \
$(MAKE) --no-print-directory -C $(RIOTBOOT_DIR) $*
# Generate a binary file from the bootloader which fills all the
# allocated space. This is used afterwards to create a combined
# binary with both bootloader and RIOT firmware with header
BOOTLOADER_BIN = $(RIOTBOOT_DIR)/bin/$(BOARD)
$(BOOTLOADER_BIN)/riotboot.extended.bin: $(BOOTLOADER_BIN)/riotboot.bin
$(Q)cp $^ $@.tmp
$(Q)truncate -s $$(($(RIOTBOOT_LEN))) $@.tmp
$(Q)mv $@.tmp $@
# Only call sub make if not already in riotboot
ifneq ($(BOOTLOADER_BIN)/riotboot.bin,$(BINFILE))
$(BOOTLOADER_BIN)/riotboot.bin: riotboot/bootloader/binfile
endif
# Create combined binary booloader + RIOT firmware with header
RIOTBOOT_COMBINED_BIN = $(BINDIR_APP)-slot0-combined.bin
riotboot/combined-slot0: $(RIOTBOOT_COMBINED_BIN)
$(RIOTBOOT_COMBINED_BIN): $(BOOTLOADER_BIN)/riotboot.extended.bin $(SLOT0_RIOT_BIN)
$(Q)cat $^ > $@
# Flashing rule for edbg to flash combined binaries
riotboot/flash-combined-slot0: HEXFILE=$(RIOTBOOT_COMBINED_BIN)
# Flashing rule for openocd to flash combined binaries
riotboot/flash-combined-slot0: ELFFILE=$(RIOTBOOT_COMBINED_BIN)
riotboot/flash-combined-slot0: $(RIOTBOOT_COMBINED_BIN) $(FLASHDEPS)
$(FLASHER) $(FFLAGS)
# Flashing rule for slot 0
riotboot/flash-slot0: export IMAGE_OFFSET=$(SLOT0_OFFSET)
# Flashing rule for edbg to flash only slot 0
riotboot/flash-slot0: HEXFILE=$(SLOT0_RIOT_BIN)
# openocd
riotboot/flash-slot0: ELFFILE=$(SLOT0_RIOT_BIN)
riotboot/flash-slot0: $(SLOT0_RIOT_BIN) $(FLASHDEPS)
$(FLASHER) $(FFLAGS)
# Targets to generate only slot 0 binary
riotboot/slot0: $(SLOT0_RIOT_BIN)
# Default flashing rule for bootloader + slot 0
riotboot/flash: riotboot/flash-slot0 riotboot/flash-bootloader
else
riotboot:
$(Q)echo "error: riotboot feature not selected! (try FEATURES_REQUIRED += riotboot)"
$(Q)false
endif # (,$(filter riotboot,$(FEATURES_USED)))