-
Notifications
You must be signed in to change notification settings - Fork 2.1k
bootloader: add riotboot minimal bootloader #10065
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2df0abf
a638f31
281d808
9cfdf6e
7a6849c
3cf33f7
f1c57b2
66911d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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 | ||
|
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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| 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. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This documentation needs uptading. We are not verifying the checksum of the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
|
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and add FEATURES_PROVIDED = riotboot ?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kYc0o actually without spaces
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
| 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) {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What's the purpose of this assignment?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The argument is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like this function should be called |
||
| { | ||
| /* 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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also an address defined as
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the representation of the address as an |
||
| { | ||
| return SCB->VTOR; | ||
| } | ||
| #endif | ||
|
|
||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| RIOTBASE := ../../.. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please remove all the instances of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does it really hurt?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
| 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 \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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/ | ||
| 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)) { | ||
|
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; | ||
| } | ||
| } | ||
| 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 */ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.