Skip to content

Conversation

@fabian18
Copy link
Contributor

@fabian18 fabian18 commented Oct 29, 2025

Contribution description

Introducing riotboot_hdr_v2.

We want to test boot an image and have an automatic revert to a previous image if a new image fails to boot.
For example due to an unexpected endless loop or compromised firmware or kernel panic.

This adds a flags field to the header to encode an image state and a number of boot attempts.
The watchdog is started in the bootloader. An image has to confirm that it booted successfully to not be labeled as DISMISSED by the bootloader.

Testing procedure

Issues/PRs references

@github-actions github-actions bot added Area: core Area: RIOT kernel. Handle PRs marked with this with care! Area: build system Area: Build system Area: tools Area: Supplementary tools Area: OTA Area: Over-the-air updates Area: sys Area: System labels Oct 29, 2025
@fabian18 fabian18 changed the title sys/riotboot: riotboot head v2 Oct 29, 2025
@fabian18
Copy link
Contributor Author

I first wanted that the flags are also covered by the checksum. But this required rewriting of the checksum and this required a page erase of the current firmware and this made the program stall.

Copy link
Contributor

@crasbe crasbe left a comment

Choose a reason for hiding this comment

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

Just some preliminary high-level styling related comments. The static test also has some warnings left.

#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"
Comment on lines +52 to +56
#if defined(MODULE_RIOTBOOT_HDR_V2)
#define RIOTBOOT_MAGIC RIOTBOOT_MAGIC_V2
#else
#define RIOTBOOT_MAGIC RIOTBOOT_MAGIC_V1
#endif
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
#if defined(MODULE_RIOTBOOT_HDR_V2)
#define RIOTBOOT_MAGIC RIOTBOOT_MAGIC_V2
#else
#define RIOTBOOT_MAGIC RIOTBOOT_MAGIC_V1
#endif
#if defined(MODULE_RIOTBOOT_HDR_V2)
# define RIOTBOOT_MAGIC RIOTBOOT_MAGIC_V2
#else
# define RIOTBOOT_MAGIC RIOTBOOT_MAGIC_V1
#endif
Comment on lines +77 to +79
#ifndef CONFIG_RIOTBOOT_MAX_ATTEMPTS
#define CONFIG_RIOTBOOT_MAX_ATTEMPTS 3u
#endif
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
#ifndef CONFIG_RIOTBOOT_MAX_ATTEMPTS
#define CONFIG_RIOTBOOT_MAX_ATTEMPTS 3u
#endif
#ifndef CONFIG_RIOTBOOT_MAX_ATTEMPTS
# define CONFIG_RIOTBOOT_MAX_ATTEMPTS 3u
#endif
* The timeout is doubled on each unsuccessful attempt.
*/
#ifndef CONFIG_RIOTBOOT_WDT_TIMEOUT_MSEC
#define CONFIG_RIOTBOOT_WDT_TIMEOUT_MSEC 4000
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
#define CONFIG_RIOTBOOT_WDT_TIMEOUT_MSEC 4000
# define CONFIG_RIOTBOOT_WDT_TIMEOUT_MSEC 4000
Comment on lines +52 to +58
switch (riotboot_hdr->v1.magic_number) {
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.version;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.version;
default:
return NULL;
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
switch (riotboot_hdr->v1.magic_number) {
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.version;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.version;
default:
return NULL;
switch (riotboot_hdr->v1.magic_number) {
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.version;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.version;
default:
return NULL;

As per our Coding Convention: https://github.com/RIOT-OS/RIOT/blob/master/CODING_CONVENTIONS.md#indentation-and-braces

Comment on lines +65 to +70
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.start_addr;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.start_addr;
default:
return NULL;
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
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.start_addr;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.start_addr;
default:
return NULL;
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.start_addr;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.start_addr;
default:
return NULL;
Comment on lines +85 to +90
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.chksum;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.chksum;
default:
return NULL;
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
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.chksum;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.chksum;
default:
return NULL;
case RIOTBOOT_MAGIC_V1:
return &riotboot_hdr->v1.chksum;
case RIOTBOOT_MAGIC_V2:
return &riotboot_hdr->v2.chksum;
default:
return NULL;
uint32_t riotboot_hdr_get_flags(const riotboot_hdr_t *riotboot_hdr);

/**
* @brief Calculate header checksum
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
* @brief Calculate header checksum
* @brief Getter for the header checksum

If I understand the code correctly, it does not calculate the checksum when calling this function, right?

@crasbe crasbe added the Type: new feature The issue requests / The PR implemements a new feature for RIOT label Oct 29, 2025
@mguetschow
Copy link
Contributor

Are the riotboot images somehow compatible with the SUIT ecosystem? If not, wouldn't it make sense to converge towards that instead of introducing yet another custom format?

@fabian18
Copy link
Contributor Author

What contradiction do you see in SUIT? From a SUIT perspective there is only binary payload.
You could say that the header does not have to be shipped with an image because it could be generated by a currently running image. This would not change the fact that there is a header and that I would like to encode an image state.

@mguetschow
Copy link
Contributor

Disclaimer: I haven't looked much into SUIT. But from my understanding, your proposed riotboot header includes metadata information about the image, that I would have expected in a SUIT manifest such as https://datatracker.ietf.org/doc/draft-ietf-suit-manifest/.

But it can well be that that metadata is disjoint from what would be carried in a SUIT manifest, in that case please just disregard my comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: build system Area: Build system Area: core Area: RIOT kernel. Handle PRs marked with this with care! Area: OTA Area: Over-the-air updates Area: sys Area: System Area: tools Area: Supplementary tools Type: new feature The issue requests / The PR implemements a new feature for RIOT

3 participants