Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,10 @@ ifneq (,$(filter periph_gpio_irq,$(USEMODULE)))
FEATURES_REQUIRED += periph_gpio
endif

ifneq (,$(filter riotboot_slot, $(USEMODULE)))
USEMODULE += riotboot_hdr
endif

# always select gpio (until explicit dependencies are sorted out)
FEATURES_OPTIONAL += periph_gpio

Expand Down
5 changes: 5 additions & 0 deletions Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions boards/common/iotlab/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

# Put other features for this board (in alphabetical order)
FEATURES_PROVIDED += riotboot

# The board MPU family (used for grouping by the CI system)
FEATURES_MCU_GROUP = cortex_m3_1
3 changes: 3 additions & 0 deletions boards/nucleo-l152re/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

# Put other features for this board (in alphabetical order)
FEATURES_PROVIDED += riotboot

# load the common Makefile.features for Nucleo boards
include $(RIOTBOARD)/common/nucleo64/Makefile.features

Expand Down
3 changes: 3 additions & 0 deletions boards/saml21-xpro/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

# Put other features for this board (in alphabetical order)
FEATURES_PROVIDED += riotboot

# The board MPU family (used for grouping by the CI system)
FEATURES_MCU_GROUP = cortex_m0_2

Expand Down
3 changes: 3 additions & 0 deletions boards/samr21-xpro/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

# Put other features for this board (in alphabetical order)
FEATURES_PROVIDED += riotboot

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I had it tested do you want to add it also to saml21-xpro board?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I can do that myself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


# The board MPU family (used for grouping by the CI system)
FEATURES_MCU_GROUP = cortex_m0_2

Expand Down
25 changes: 25 additions & 0 deletions bootloaders/riotboot/Makefile
Original file line number Diff line number Diff line change
@@ -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
Comment thread
jcarrano marked this conversation as resolved.
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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the :=?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variable needs to be evaluated at the moment of its parsing, since the value is taken as a reference for further calculations. Otherwise the value changes and the results are non-consistent.

75 changes: 75 additions & 0 deletions bootloaders/riotboot/README.md
Original file line number Diff line number Diff line change
@@ -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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documentation needs uptading. We are not verifying the checksum of the image put the metadata right ?
Also a bit of the same confusion between image and slot and metadata.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will try to read carefully everything and be consistent on the naming, since I agree it's confusing.


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:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add "```" before and after figure to improve the layout.

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and add FEATURES_PROVIDED = riotboot ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you're right, I'll change quickly.

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

@emmanuelsearch emmanuelsearch Oct 22, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kYc0o Should the documentation state at this point that in the application makefile (here in hello-world) you need to add FEATURES_REQUIRED += riotboot ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@emmanuelsearch emmanuelsearch Oct 23, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kYc0o actually without spaces FEATURES_REQUIRED=riotboot else it fails.
And how about adding term at the end of the command?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, I just took it from the makefile so didn't mind the spaces, I'll correct it.

binary.

A comprehensive test is available at tests/riotboot.
46 changes: 46 additions & 0 deletions bootloaders/riotboot/main.c
Original file line number Diff line number Diff line change
@@ -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) {}
}
8 changes: 8 additions & 0 deletions cpu/cortexm_common/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,11 @@ TOOLCHAINS_SUPPORTED = gnu llvm
LINKFLAGS += $(if $(ROM_OFFSET),$(LINKFLAGPREFIX)--defsym=_rom_offset=$(ROM_OFFSET))
# FW_ROM_LEN: rom length to use for firmware linking. Allows linking only in a section of the rom.
LINKFLAGS += $(if $(FW_ROM_LEN),$(LINKFLAGPREFIX)--defsym=_fw_rom_length=$(FW_ROM_LEN))


# Configure riotboot bootloader and slot lengths
# 4KB are currently enough
RIOTBOOT_LEN ?= 0x1000
# Take the whole flash minus RIOTBOOT_LEN
SLOT0_LEN ?= $(shell printf "0x%x" $$(($(ROM_LEN:%K=%*1024)-$(RIOTBOOT_LEN))))
SLOT0_LEN := $(SLOT0_LEN)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this assignment?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The calculations done in the line above are only performed at the end of the make parsing, but the value should be consistent across the whole process. This ensures the value is calculated and preserved as is.

38 changes: 38 additions & 0 deletions cpu/cortexm_common/include/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,44 @@ static inline void cortexm_isr_end(void)
}
}

/**
* @brief Jumps to another image in flash
*
* This function is supposed to be called by a bootloader application.
*
* @param[in] image_address address in flash of other image
*/
static inline void cpu_jump_to_image(uint32_t image_address)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The argument is image_address so should be declared as an address type. As there is currently no reason to limit to 32bit or cortexm_common in the cpu_jump_to_image I would declare it as void *.

@kYc0o kYc0o Oct 8, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As there is currently no reason to limit to 32bit or cortexm_common in the cpu_jump_to_image I would declare it as void *.

Yes there is: it doesn't (and would never) exist a cortex-m cpu which is not 32bit. Moreover, only certain cortex-m (already ifdef'd) support the relocation of the vector table (VTOR). Thus this code is not meant to be executed by any other architecture.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this function should be called jump_to_address? Since it's being passed an address, not an image number

{
/* Disable IRQ */
__disable_irq();

/* set MSP */
__set_MSP(*(uint32_t*)image_address);

/* skip stack pointer */
image_address += 4;

/* load the images reset_vector address */
uint32_t destination_address = *(uint32_t*)image_address;

/* Make sure the Thumb State bit is set. */
destination_address |= 0x1;

/* Branch execution */
__asm("BX %0" :: "r" (destination_address));
}

/* The following register is only present for Cortex-M0+, -M3, -M4 and -M7 CPUs */
#if defined(CPU_ARCH_CORTEX_M0PLUS) || defined(CPU_ARCH_CORTEX_M3) || \
defined(CPU_ARCH_CORTEX_M4) || defined(CPU_ARCH_CORTEX_M4F) || \
defined(CPU_ARCH_CORTEX_M7)
static inline uint32_t cpu_get_image_baseaddr(void)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also an address defined as uint32_t.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the representation of the address as an uint32_t eases quite a lot the usage of the function, taking into account that the vendor headers define addresses as unsigned integer constants. Changing everything into pointer makes the coding more complex and one can be easily lost casting those pointers.

{
return SCB->VTOR;
}
#endif

#ifdef __cplusplus
}
#endif
Expand Down
39 changes: 39 additions & 0 deletions dist/tools/riotboot_gen_hdr/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
RIOTBASE := ../../..

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove all the instances of :=

@kYc0o kYc0o Dec 11, 2018

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it really hurt?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because a few months from now, and nobody will know if the immediate assignments were necessary or not and if they can be safely removed.

And also (and this has nothing to do with the bootloader) it perpetuates the myth that := is a sort of magical spell that one puts when things don't work.

RIOT_INCLUDE := $(RIOTBASE)/sys/include
RIOT_CORE_INC := $(RIOTBASE)/core/include
NATIVE_INCLUDE := $(RIOTBASE)/cpu/native/include
COMMON_SRC := common.c
COMMON_HDR := common.h

RIOT_HDR_SRC := \
$(RIOTBASE)/sys/checksum/fletcher32.c \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it correct to peek into the contents of a module? I feel this violates module encapsulation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compilation of the tools is a complete separated process, actually in a complete different environment. This line only makes (re)use of the C file, which has no dependencies so it's just like copy/pase it.

$(RIOTBASE)/sys/riotboot/hdr.c

RIOT_HDR_HDR := $(RIOT_INCLUDE)/riotboot/hdr.h \
$(RIOT_INCLUDE)/checksum/fletcher32.h \
$(RIOTBASE)/core/include/byteorder.h

GENHDR_SRC := $(COMMON_SRC) $(RIOT_HDR_SRC) \
main.c genhdr.c

GENHDR_HDR := $(COMMON_HDR) $(RIOT_HDR_HDR)

CFLAGS += -g -I. -O3 -Wall -Wextra -pedantic -std=c99

ifeq ($(QUIET),1)
Q=@
else
Q=
endif

all: bin/genhdr

bin/:
$(Q)mkdir -p bin

bin/genhdr: $(GENHDR_HDR) $(GENHDR_SRC) Makefile | bin/
$(Q)$(CC) $(CFLAGS) -I$(RIOT_INCLUDE) -I$(RIOT_CORE_INC) \
-I$(NATIVE_INCLUDE) $(GENHDR_SRC) -o $@

clean:
$(Q)rm -rf bin/
39 changes: 39 additions & 0 deletions dist/tools/riotboot_gen_hdr/common.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/

/**
* @file
* @brief Common tools for RIOT images header generation
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/

#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

int to_file(const char *filename, void *buf, size_t len)
{
int fd;

if (strcmp("-", filename)) {
Comment thread
danpetry marked this conversation as resolved.
fd = open(filename, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
}
else {
fd = STDOUT_FILENO;
}

if (fd > 0) {
ssize_t res = write(fd, buf, len);
close(fd);
return res == (ssize_t)len;
}
else {
return fd;
}
}
31 changes: 31 additions & 0 deletions dist/tools/riotboot_gen_hdr/common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2017 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU General Public
* License v2. See the file LICENSE for more details.
*/

#ifndef COMMON_H
#define COMMON_H

#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Write len bytes of a given buffer into a file
*
* @param[out] filename name of the file to be written
* @param[in] buf a pointer to the buffer which needs to be written
* @param[in] len the number of bytes from buf to be written
*
*/
int to_file(const char *filename, void *buf, size_t len);

#ifdef __cplusplus
} /* end extern "C" */
#endif

#endif /* COMMON_H */
Loading