Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions bootloaders/riotboot/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ APPLICATION = riotboot

# Include riotboot flash partition functionality
USEMODULE += riotboot_slot
USEMODULE += riotboot_flashwrite
USEMODULE += riotboot_wdt

# We don't want to re-configure any hardware
CFLAGS += -DDISABLE_BOARD_INIT=1
Expand Down
52 changes: 45 additions & 7 deletions bootloaders/riotboot/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,69 @@
* @}
*/

#include <string.h>

#include "cpu.h"
#include "panic.h"
#include "periph/flashpage.h"
#include "riotboot/hdr.h"
#include "riotboot/slot.h"
#include "riotboot/flashwrite.h"
#include "riotboot/wdt.h"

void kernel_init(void)
{
uint32_t version = 0;
int slot = -1;

uint32_t version;
int slot;
int state;
INIT:
version = 0;
slot = -1;
for (unsigned i = 0; i < riotboot_slot_numof; i++) {
const riotboot_hdr_t *riot_hdr = riotboot_slot_get_hdr(i);
if (riotboot_slot_validate(i)) {
/* skip slot if metadata broken */
continue;
}
if (riot_hdr->start_addr != riotboot_slot_get_image_startaddr(i)) {
if (riotboot_hdr_get_start_addr(riot_hdr) !=
riotboot_slot_get_image_startaddr(i)) {
continue;
}
state = riotboot_hdr_get_img_state(riot_hdr);
if (state == RIOTBOOT_HDR_IMG_STATE_INSTALLED ||
state == RIOTBOOT_HDR_IMG_STATE_DISMISSED) {
/* skip image which previously failed to boot or is not yet activated */
continue;
}
if (slot == -1 || riot_hdr->version > version) {
version = riot_hdr->version;
if (slot == -1 || riotboot_hdr_get_version(riot_hdr) > version) {
version = riotboot_hdr_get_version(riot_hdr);
slot = i;
}
}

unsigned boot = 0;
if (slot != -1) {
riotboot_hdr_t riot_hdr = *riotboot_slot_get_hdr(slot);
if (riotboot_hdr_is_v2(&riot_hdr)) {
boot = riotboot_hdr_get_boot_count(&riot_hdr);
if (state == RIOTBOOT_HDR_IMG_STATE_ACTIVATED) {
/* not yet confirmed */
if (boot == CONFIG_RIOTBOOT_MAX_ATTEMPTS) {
/* failed to boot for CONFIG_RIOTBOOT_MAX_ATTEMPTS attempts */
riotboot_hdr_set_img_state(&riot_hdr, RIOTBOOT_HDR_IMG_STATE_DISMISSED);
goto INIT; /* choose different slot */
}
else {
riotboot_hdr_set_boot_count(&riot_hdr, boot + 1);
}
}
if (memcmp(&riot_hdr, riotboot_slot_get_hdr(slot), sizeof(riot_hdr.v2))) {
flashpage_write(flashpage_addr(flashpage_page(riotboot_slot_get_hdr(slot))),
&riot_hdr.v2, sizeof(riot_hdr.v2));
}
}
#if IS_USED(MODULE_RIOTBOOT_WDT)
riotboot_wdt_start(CONFIG_RIOTBOOT_WDT_TIMEOUT_MSEC << boot);
#endif
riotboot_slot_jump(slot);
}

Expand Down
9 changes: 8 additions & 1 deletion core/lib/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
#include "periph/pm.h"
#include "thread.h"
#include "stdio_base.h"

#if IS_USED(MODULE_RIOTBOOT)
#include "riotboot/wdt.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
#include "riotboot/wdt.h"
# include "riotboot/wdt.h"

#endif
#if IS_USED(MODULE_VFS)
#include "vfs.h"
#endif
Expand Down Expand Up @@ -60,6 +62,11 @@ static void *main_trampoline(void *arg)
LOG_INFO(CONFIG_BOOT_MSG_STRING "\n");
}

#if IS_USED(MODULE_RIOTBOOT)
if (IS_USED(MODULE_RIOTBOOT_HDR_MAIN_CONFIRM)) {
riotboot_wdt_stop();
}
#endif
int res = main();

if (IS_USED(MODULE_TEST_UTILS_MAIN_EXIT_CB)) {
Expand Down
98 changes: 74 additions & 24 deletions dist/tools/riotboot_gen_hdr/genhdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,38 @@
*/
#define HDR_ALIGN (256)

static void populate_hdr(riotboot_hdr_t *hdr, uint32_t ver, uint32_t addr)
static size_t populate_hdr_v1(riotboot_hdr_t *hdr, uint32_t ver, uint32_t addr)
{
/* ensure the buffer and header have 0's */
memset(hdr, '\0', sizeof(riotboot_hdr_t));

/* Generate image header */
hdr->magic_number = RIOTBOOT_MAGIC;
hdr->version = ver;
hdr->start_addr = addr;
memset(hdr, '\0', sizeof(*hdr));
/* Generate image header v1 */
hdr->v1.magic_number = RIOTBOOT_MAGIC_V1;
hdr->v1.version = ver;
hdr->v1.start_addr = addr;
/* calculate header checksum */
hdr->v1.chksum = riotboot_hdr_checksum(hdr);
return sizeof(hdr->v1);
}

static size_t populate_hdr_v2(riotboot_hdr_t *hdr, uint32_t ver, uint32_t addr)
{
/* ensure the buffer and header have 0's */
memset(hdr, '\0', sizeof(*hdr));
/* Generate image header v2 */
hdr->v2.magic_number = RIOTBOOT_MAGIC_V2;
hdr->v2.version = ver;
hdr->v2.start_addr = addr;
hdr->v2.flags = 0xffffffff;
hdr->v2.flags &= ~RIOTBOOT_HDR_IMAGE_STATE_MASK;
hdr->v2.flags |= (RIOTBOOT_HDR_IMG_STATE_ACTIVATED << RIOTBOOT_HDR_IMAGE_STATE_SHIFT);
/* calculate header checksum */
hdr->chksum = riotboot_hdr_checksum(hdr);
hdr->v2.chksum = riotboot_hdr_checksum(hdr);
return sizeof(hdr->v2);
}

int genhdr(int argc, char *argv[])
{
const char generate_usage[] = "<IMG_BIN> <APP_VER> <START_ADDR> <HDR_LEN> <outfile|->";
const char generate_usage[] = "<IMG_BIN> <APP_VER> <START_ADDR> <HDR_LEN> <outfile|-> [-v [v1,v2]]";

Check warning on line 62 in dist/tools/riotboot_gen_hdr/genhdr.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters

/* riotboot_hdr buffer */
uint8_t *hdr_buf;
Expand Down Expand Up @@ -93,14 +108,41 @@
hdr_len = hdr_len_arg;
}

/* generate only v1 by default */
bool gen_v1 = true;
bool gen_v2 = false;
if (argc >= 8) {
gen_v1 = false;
if (!strcmp(argv[6], "-v")) {
for (int a = 7; a < argc; a++) {
if (!strcmp(argv[a], "v1")) {
gen_v1 = true;
}
else if (!strcmp(argv[a], "v2")) {
gen_v2 = true;
}
else {
fprintf(stderr, "Error: unknown version '%s'!\n", argv[a]);
return -1;
}
}
}
}
/* prepare a 0 initialised buffer for riotboot_hdr_t */
hdr_buf = calloc(1, hdr_len);
if (hdr_buf == NULL) {
fprintf(stderr, "Error: not enough memory!\n");
return -1;
}

populate_hdr((riotboot_hdr_t*)hdr_buf, app_ver, start_addr);
size_t gen_hdr_size = 0;
uint8_t *p_hdr = hdr_buf;
if (gen_v1) {
gen_hdr_size += populate_hdr_v1((riotboot_hdr_t *)(p_hdr + gen_hdr_size), app_ver, start_addr);

Check warning on line 141 in dist/tools/riotboot_gen_hdr/genhdr.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
}
if (gen_v2) {
gen_hdr_size += populate_hdr_v2((riotboot_hdr_t *)(p_hdr + gen_hdr_size), app_ver, start_addr);

Check warning on line 144 in dist/tools/riotboot_gen_hdr/genhdr.c

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
}

/* Write the header */
if (!to_file(argv[5], hdr_buf, hdr_len)) {
Expand All @@ -124,35 +166,43 @@

riotboot_hdr_t hdr = { 0 };
int res = from_file(file, &hdr, sizeof(hdr));
if (res < (int)sizeof(hdr)) {
if (res < (int)sizeof(hdr.v1)) {
fprintf(stderr, "Can't read header from %s\n", file);
return -EIO;
}

if (hdr.magic_number != RIOTBOOT_MAGIC) {
fprintf(stderr, "Invalid magic: %x\n", hdr.magic_number);
uint32_t magic = riotboot_hdr_get_magic_number(&hdr);
if (magic == RIOTBOOT_MAGIC_V2) {
hdr.v2.magic_number = RIOTBOOT_MAGIC_V2;
hdr.v2.version = atoi(argv[2]);
hdr.v2.chksum = riotboot_hdr_checksum(&hdr);
to_file(file, &hdr, sizeof(hdr.v2));
}
else if (magic == RIOTBOOT_MAGIC_V1) {
hdr.v1.magic_number = RIOTBOOT_MAGIC_V1;
hdr.v1.version = atoi(argv[2]);
hdr.v1.chksum = riotboot_hdr_checksum(&hdr);
to_file(file, &hdr, sizeof(hdr.v1));
}
else {
fprintf(stderr, "Invalid magic: %x\n", magic);
return -EIO;
}

hdr.version = atoi(argv[2]);
hdr.chksum = riotboot_hdr_checksum(&hdr);
to_file(file, &hdr, sizeof(hdr));

return 0;
}

static void print_hdr(const riotboot_hdr_t *hdr)
{
printf("version: %u\n", hdr->version);
printf("address: 0x%x\n", hdr->start_addr);
printf("version: %u\n", riotboot_hdr_get_version(hdr));
printf("address: 0x%x\n", riotboot_hdr_get_start_addr(hdr));
printf("checksum: %svalid\n", riotboot_hdr_validate(hdr) ? "in" : "");
}

static void print_hdr_json(const riotboot_hdr_t *hdr)
{
printf("{\n");
printf("\t\"version\": %u,\n", hdr->version);
printf("\t\"address\": %u,\n", hdr->start_addr);
printf("\t\"version\": %u,\n", riotboot_hdr_get_version(hdr));
printf("\t\"address\": %u,\n", riotboot_hdr_get_start_addr(hdr));
printf("\t\"valid\": %s\n", riotboot_hdr_validate(hdr) ? "false" : "true");
printf("}\n");
}
Expand All @@ -166,8 +216,8 @@
return -EIO;
}

if (hdr.magic_number != RIOTBOOT_MAGIC) {
fprintf(stderr, "Invalid magic: %x\n", hdr.magic_number);
if (riotboot_hdr_get_magic_number(&hdr) != RIOTBOOT_MAGIC) {
fprintf(stderr, "Invalid magic: %x\n", riotboot_hdr_get_magic_number(&hdr));
return -EIO;
}

Expand Down
10 changes: 9 additions & 1 deletion makefiles/boot/riotboot.mk
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ $(BINDIR_RIOTBOOT)/%.elf: $(BASELIBS) $(ARCHIVES) $(BINDIR_RIOTBOOT)
$(Q)$(_LINK) -o $@
endif

RIOTBOOT_HDR_VERSION ?= -v
ifneq (,$(filter riotboot_hdr_v1, $(USEMODULE)))
RIOTBOOT_HDR_VERSION := $(RIOTBOOT_HDR_VERSION) v1
endif
ifneq (,$(filter riotboot_hdr_v2, $(USEMODULE)))
RIOTBOOT_HDR_VERSION := $(RIOTBOOT_HDR_VERSION) v2
endif

# Slot 0 and 1 firmware offset, after header
SLOT0_IMAGE_OFFSET := $$(($(SLOT0_OFFSET) + $(RIOTBOOT_HDR_LEN)))
SLOT1_IMAGE_OFFSET := $$(($(SLOT1_OFFSET) + $(RIOTBOOT_HDR_LEN)))
Expand Down Expand Up @@ -70,7 +78,7 @@ $(HEADER_TOOL): FORCE
# 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) - > $@
$(HEADER_TOOL) generate $< $(APP_VER) $$(($(ROM_START_ADDR)+$(OFFSET))) $(RIOTBOOT_HDR_LEN) - $(RIOTBOOT_HDR_VERSION) > $@

$(BINDIR_RIOTBOOT)/slot0.hdr: OFFSET=$(SLOT0_IMAGE_OFFSET)
$(BINDIR_RIOTBOOT)/slot1.hdr: OFFSET=$(SLOT1_IMAGE_OFFSET)
Expand Down
5 changes: 3 additions & 2 deletions sys/include/riotboot/flashwrite.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,16 @@ int riotboot_flashwrite_finish_raw(riotboot_flashwrite_t *state,
* @brief Finish a firmware update (riotboot version)
*
* This function finishes a firmware update by re-writing the first header so
* it includes riotboot's magic number ("RIOT").
* it includes riotboot's magic number.
*
* @param[in] state ptr to previously used state structure
*
* @returns 0 on success, <0 otherwise
*/
static inline int riotboot_flashwrite_finish(riotboot_flashwrite_t *state)
{
return riotboot_flashwrite_finish_raw(state, (const uint8_t *)"RIOT",
uint32_t magic = RIOTBOOT_MAGIC;
return riotboot_flashwrite_finish_raw(state, (const uint8_t *)&magic,
RIOTBOOT_FLASHWRITE_SKIPLEN);
}

Expand Down
Loading
Loading