suit/storage/flashwrite: derive slot version from SUIT manifest seq_number
Contribution description
The SUIT manifest should be the single source of truth. If we want to support roll-backs, the backend will generate a new manifest for an existing firmware revision.
Updating the riotboot header in the backend would require us to maintain an actual separate firmware version, instead we want the manifest to just point to an existing one.
For this, populate the riotboot header with the sequence number from the SUIT maninfest.
Testing procedure
_dtv_verify_image_match() doesn't actually check the flash content, so we only have to make sure the page in RAM has the expected state.
2025-05-27 21:22:05,748 # Finalizing payload store
2025-05-27 21:22:05,751 # Executing handler with key 3
2025-05-27 21:22:05,753 # Verifying image digest
2025-05-27 21:22:05,757 # Starting digest verification against image
2025-05-27 21:22:05,760 # verify 132284 payload bytes (indirect)
2025-05-27 21:22:05,861 # Install correct payload
2025-05-27 21:22:05,864 # patch header version 1748351058 -> 10
2025-05-27 21:22:05,867 # Verified installed payload
2025-05-27 21:22:05,869 # Leaving sequence handler
2025-05-27 21:22:05,872 # Executing handler with key 10
2025-05-27 21:22:05,876 # Handling command sequence starting with CBOR type 2
2025-05-27 21:22:05,879 # Handling command sequence
2025-05-27 21:22:05,881 # Executing handler with key 3
2025-05-27 21:22:05,883 # Verifying image digest
2025-05-27 21:22:05,887 # Starting digest verification against image
2025-05-27 21:22:05,890 # verify 132284 payload bytes (indirect)
2025-05-27 21:22:05,991 # Verified installed payload
2025-05-27 21:22:05,994 # Leaving sequence handler
2025-05-27 21:22:05,996 # Leaving sequence handler
2025-05-27 21:22:05,998 # Leaving sequence handler
2025-05-27 21:22:06,001 # Image magic_number: 0x544f4952
2025-05-27 21:22:06,003 # Image Version: 0x0000000a
2025-05-27 21:22:06,006 # Image start address: 0x00082400
2025-05-27 21:22:06,008 # Header chksum: 0xa5aac1b3
2025-05-27 21:22:06,008 #
2025-05-27 21:22:07,011 # suit_worker: update successful
2025-05-27 21:22:07,013 # suit_worker: rebooting...
2025-05-27 21:22:07,049 # main(): This is RIOT! (Version: 2025.07-devel-250-g97d80-riotboot_suit_seq_number)
2025-05-27 21:22:07,052 # RIOT SUIT update example application
2025-05-27 21:22:07,053 # Running from slot 1
2025-05-27 21:22:07,056 # Image magic_number: 0x544f4952
2025-05-27 21:22:07,058 # Image Version: 0x0000000a
2025-05-27 21:22:07,061 # Image start address: 0x00082400
2025-05-27 21:22:07,064 # Header chksum: 0xa5aac1b3
2025-05-27 21:22:07,064 #
2025-05-27 21:22:07,065 # Starting the shell
Issues/PRs references
Murdock results
:heavy_check_mark: PASSED
7a5ad1dc1dee0e9e6ec81ffed6ba806e597b77bd suit/storage/flashwrite: get slot version from SUIT manifest seq_number
| Success | Failures | Total | Runtime |
|---|---|---|---|
| 10379 | 0 | 10379 | 10m:43s |
Artifacts
The riotboot header version that is sent in the payload is patched with the manifest sequence number.
riotboot.mk and suit.inc.mk bothe have:
EPOCH = $(call memoized,EPOCH,$(shell date +%s))
APP_VER ?= $(EPOCH)
The riot header version and manifest sequence number are both set to APP_VER by default. A rollback (downgrade) will carry an image with an old APP_VER but the manifest carries a new sequence number? That means the new manifest must be created using the old images to compute the old image digests.
This explains why this PR is necessary?
The idea is that we don't want to generate a new firmware image for the roll-back, just a new manifest. The new manifest can then still point to the old firmware image URL.
Otherwise, when we roll-back device A but not device B, device A would always need a separate firmware image for all the future as it's at a different revision then.
In hindsight it turns out that adding the riotboot header to the firmware image is entirely superfluous as it can be entirely generated on the fly when downloading the image via SUIT / riotboot_flashwrite.
But changing that would be a breaking change.
In hindsight it turns out that adding the riotboot header to the firmware image is entirely superfluous as it can be entirely generated on the fly when downloading the image via SUIT / riotboot_flashwrite.
But changing that would be a breaking change.
Wouldn't that still be the better course long-term?
Maybe can support for a migration time both variants. To my understanding we could detect if a firmware already contains a header due to the magic number. If the header is there, we could strip it for handling, but honor the header for the checksum.
After some time we could drop the handling of the special case with the header being part of the firmware.
Or am I overlooking something?
Having an option to ship an image with or without riotboot header sounds most flexible. But if this PR is already providing a benefit, its not an either-this-or-that decision IMO
As a thought, the Application version in the riotboot header that you override with the manifest sequence counter could be a define in riotbuild.h. A firmware image version is not dynamic. So I think it is appropriate that it is a constant in the image.
Then, the difference could be made clear in the "version" shell command when the app version (constant define) and the suit sequence counter (as in the riotboot header) are printed.