-
Notifications
You must be signed in to change notification settings - Fork 2.1k
sys: provide over-the-air update mechanism #8902
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
41c8ccc
e76031b
d7523e8
1a6c925
9ee8444
6806085
cbf324a
17d5596
09a6a3d
d1f54c5
a885007
05c17e8
c01eb23
16dfec7
58887f4
5e35628
3ab924b
ff39a89
11c96f7
719d0f9
7ac7411
49788a0
1bb4fe0
0ab298f
d2ad1a0
a122045
1087b6d
2ac74b3
6a0ec11
d4ca843
143db71
714ba81
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 |
|---|---|---|
| @@ -1,5 +1,7 @@ | ||
| /* | ||
| * Copyright (C) 2017 Inria | ||
| * 2018 Kaspar Schleiser <[email protected]> | ||
| * | ||
| * | ||
| * 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 | ||
|
|
@@ -14,16 +16,17 @@ | |
| * @brief Memory definitions for the Cortex-M family | ||
| * | ||
| * @author Francisco Acosta <[email protected]> | ||
| * @author Kaspar Schleiser <[email protected]> | ||
| * | ||
| * @} | ||
| */ | ||
|
|
||
| _boot_offset = DEFINED( _rom_offset ) ? _rom_offset : 0x0 ; | ||
| _rom_offset = DEFINED( _rom_offset ) ? _rom_offset : 0x0 ; | ||
|
|
||
| MEMORY | ||
| { | ||
| rom (rx) : ORIGIN = _rom_start_addr + _boot_offset, LENGTH = _rom_length - _boot_offset | ||
| ram (w!rx) : ORIGIN = _ram_start_addr, LENGTH = _ram_length | ||
| rom (rx) : ORIGIN = _rom_start_addr + _rom_offset, LENGTH = _rom_length | ||
| ram (w!rx) : ORIGIN = _ram_start_addr, LENGTH = _ram_length | ||
| } | ||
|
|
||
| INCLUDE cortexm_base.ld | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| APPLICATION = riotboot | ||
|
|
||
| BOARD ?= samr21-xpro | ||
|
|
||
| USEMODULE += firmware | ||
|
|
||
| CFLAGS += -DNDEBUG -DLOG_LEVEL=LOG_NONE | ||
| DISABLE_MODULE += auto_init | ||
|
|
||
| RIOTBASE ?= $(CURDIR)/../.. | ||
|
|
||
| include $(RIOTBASE)/Makefile.include |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Overview | ||
|
|
||
| This folder contains a simple bootloader that allows ping-pong style | ||
| over-the-air updates. | ||
|
|
||
| Please see examples/ota as example. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| /* | ||
| * Copyright (C) 2017 Kaspar Schleiser <[email protected]> | ||
| * 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. | ||
| */ | ||
|
|
||
| /** | ||
| * @ingroup bootloader | ||
| * @{ | ||
| * | ||
| * @file | ||
| * @brief RIOT Bootloader | ||
| * | ||
| * @author Kaspar Schleiser <[email protected]> | ||
| * @author Francisco Acosta <[email protected]> | ||
| * | ||
| * @} | ||
| */ | ||
|
|
||
| #include "firmware.h" | ||
| #include "cpu.h" | ||
| #include "panic.h" | ||
|
|
||
| void kernel_init(void) | ||
| { | ||
| uint32_t version = 0; | ||
| uint32_t slot = 0; | ||
|
|
||
| /* skip slot 0 (which points to the bootloader) */ | ||
| for (unsigned i = 1; i < firmware_num_slots; i++) { | ||
| firmware_metadata_t *slot_metadata = firmware_get_metadata(i); | ||
| if (firmware_validate_metadata_checksum(slot_metadata)) { | ||
| /* skip slot if metadata broken */ | ||
| continue; | ||
| } | ||
| if (slot_metadata->start_addr != firmware_get_image_startaddr(i)) { | ||
| continue; | ||
| } | ||
| if (!slot || slot_metadata->version > version) { | ||
| version = slot_metadata->version; | ||
| slot = i; | ||
| } | ||
| } | ||
|
|
||
| if (slot) { | ||
| firmware_jump_to_slot(slot); | ||
| } | ||
|
|
||
| /* serious trouble! */ | ||
|
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 ?
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 hope noone ever finds out.
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. If all the conditions to boot an image are not met, the bootloader boots nothing, which indeed, is serious trouble...
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. Thanks for the clarification, that I think should replace the 'serious trouble' comment for clarity. But then, in this case, why is the endless while loop required ?
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. It is intended to provide a defined error behaviour. |
||
| 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 |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| PKG_NAME = tweetnacl | ||
| PKG_URL = https://github.com/RIOT-OS/tweetnacl | ||
| PKG_VERSION = 7ea05c7098a16c87fa66e9166ce301666f3f2623 | ||
| PKG_LICENSE = PD | ||
| PKG_BUILDDIR = bin/tweetnacl_src | ||
| GITCACHE = ../git/git-cache | ||
|
|
||
| RIOTBASE := ../../.. | ||
| RIOT_INCLUDE := $(RIOTBASE)/sys/include | ||
| SHA256_DIR := $(RIOTBASE)/sys/hashes | ||
| SHA256_INCLUDE := $(RIOT_INCLUDE)/hashes | ||
| TWEETNACL_DIR := $(PKG_BUILDDIR) | ||
| TWEETNACL_SRC := $(TWEETNACL_DIR)/tweetnacl.c randombytes.c | ||
| TWEETNACL_HDR := $(TWEETNACL_DIR)/tweetnacl.h | ||
| COMMON_SRC := common.c | ||
| COMMON_HDR := common.h | ||
|
|
||
| RIOT_FIRMWARE_SRC := \ | ||
| $(SHA256_DIR)/sha256.c \ | ||
| $(RIOTBASE)/sys/checksum/fletcher32.c \ | ||
| $(RIOTBASE)/sys/firmware/firmware.c \ | ||
| $(RIOTBASE)/sys/firmware/firmware_simple.c | ||
|
|
||
| RIOT_FIRMWARE_HDR := $(RIOT_INCLUDE)/firmware.h \ | ||
| $(RIOT_INCLUDE)/hashes/sha256.h \ | ||
| $(RIOT_INCLUDE)/checksum/fletcher32.h | ||
|
|
||
| FIRMWARE_SRC := $(COMMON_SRC) $(TWEETNACL_SRC) $(RIOT_FIRMWARE_SRC) \ | ||
| main.c verify.c genkeys.c sign.c | ||
|
|
||
| FIRMWARE_HDR := $(COMMON_HDR) $(RIOT_FIRMWARE_HDR) | ||
|
|
||
| CFLAGS += -g -I. -O3 -Wall -Wextra -pedantic -std=c99 | ||
|
|
||
| all: bin/firmware | ||
|
|
||
| bin/: | ||
| mkdir -p bin | ||
|
|
||
| bin/firmware: git-download $(FIRMWARE_HDR) $(FIRMWARE_SRC) Makefile | bin/ | ||
| $(CC) $(CFLAGS) -I$(RIOT_INCLUDE) -I$(TWEETNACL_DIR) $(FIRMWARE_SRC) -o $@ | ||
|
|
||
| clean:: | ||
| rm -rf bin/firmware | ||
|
|
||
| include $(RIOTBASE)/pkg/pkg.mk |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| /* | ||
| * Copyright (C) 2017 Kaspar Schleiser <[email protected]> | ||
| * | ||
| * This file is subject to the terms and conditions of the GNU General Public | ||
| * License v2. See the file LICENSE for more details. | ||
| */ | ||
|
|
||
| #include <fcntl.h> | ||
| #include <string.h> | ||
| #include <sys/stat.h> | ||
| #include <unistd.h> | ||
|
|
||
| #include "hashes/sha256.h" | ||
|
|
||
| off_t fsize(const char *filename) | ||
| { | ||
| struct stat st; | ||
|
|
||
| if (stat(filename, &st) == 0) { | ||
| return st.st_size; | ||
| } | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| int to_file(const char *filename, void *buf, size_t len) | ||
| { | ||
| int fd; | ||
|
|
||
| if (strcmp("-", filename)) { | ||
| 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; | ||
| } | ||
| } | ||
|
|
||
| int from_file(const char *filename, void *buf, size_t len) | ||
| { | ||
| int fd = open(filename, O_RDONLY); | ||
|
|
||
| if (fd > 0) { | ||
| ssize_t res = read(fd, buf, len); | ||
| close(fd); | ||
| return res == (ssize_t)len; | ||
| } | ||
| else { | ||
| return fd; | ||
| } | ||
| } | ||
|
|
||
| ssize_t do_sha256(const char *filename, void *tgt, off_t offset) | ||
| { | ||
| sha256_context_t sha256; | ||
|
|
||
| sha256_init(&sha256); | ||
|
|
||
| ssize_t bytes_read; | ||
| ssize_t total = 0; | ||
| char buf[1024]; | ||
|
|
||
| int fd = open(filename, O_RDONLY); | ||
| if (!fd) { | ||
| return -1; | ||
| } | ||
|
|
||
| if (offset) { | ||
| if (lseek(fd, offset, SEEK_SET) == -1) { | ||
| return -1; | ||
| } | ||
| } | ||
|
|
||
| while ((bytes_read = read(fd, buf, sizeof(buf)))) { | ||
| sha256_update(&sha256, buf, bytes_read); | ||
| total += bytes_read; | ||
| } | ||
|
|
||
| sha256_final(&sha256, tgt); | ||
|
|
||
| close(fd); | ||
|
|
||
| return total; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| /* | ||
| * Copyright (C) 2017 Kaspar Schleiser <[email protected]> | ||
| * | ||
| * 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 | ||
|
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. Maybe use a more strict header guard ? (FIRMWARE_COMMON_H ?)
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. it is a local header file. change when there's a clash? |
||
| #define COMMON_H | ||
|
|
||
| #include <unistd.h> | ||
| #include <sys/types.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| off_t fsize(const char *filename); | ||
|
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. Undocumented functions
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. internal functions
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. @kaspar030 you might however prefix with |
||
| int to_file(const char *filename, void *buf, size_t len); | ||
| int from_file(const char *filename, void *buf, size_t len); | ||
| int do_sha256(const char *filename, void *tgt, size_t offset); | ||
|
|
||
| #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.
What about simply calling the parent directory
bootloader?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.
are you suggesting to change the name "riotboot"? there might be other bootloaders coming.
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.
I still think the bootloader should be at the root of RIOT. Even if other bootlaoders come, we'll have a very hard time to integrate them into the base code, at best, they'll come as packages. Any strong reason/motivation to keep it in dist? It's not even possible to compile it/use it outside RIOT...