infrastructure
More...
infrastructure
SUIT firmware storage backends
Storage backend functions for SUIT manifests
- Author
- Koen Zandberg koen@.nosp@m.berg.nosp@m.zand..nosp@m.net
The interface defined here specifies a generic API for SUIT OTA storage backends.
The driver allows for creating multiple backends, each possibly servicing multiple locations. An example of this is a VFS storage backend. This backend could service multiple file locations on a filesystem.
A SUIT component ID is formatted as an array of bytestrings. To make it easy to match and use a string, the location is supplied as string, each component separated by a separator provided in the driver. If no separator (\0
) is set, the components are concatenated without separator. The suit_storage_driver_t::set_active_location must be called before starting operations on the backend.
A write sequence by the caller must start with suit_storage_driver_t::start. The total length of the image is supplied to allow the backend to check if the payload fits in the available space. The payload data can be supplied piecewise with multiple calls to suit_storage_driver_t::write. The caller is free to specify the offset, but the backend may enforce strict monotonicity on the offset and may enforce the gapless writes. After all bytes are supplied, the suit_storage_driver_t::finish function must be called to signal the end of the write stage.
Only when the suit_storage_driver_t::install is called, the payload must be marked as valid. The mechanism for this can be backend specific. However in the case of a firmware image, it must not be bootable before this function is called. Similarly, a file payload must not be available at its provided path until after this function is called. The reason behind this is that the payload often must first be stored on the device before the image_match is called by the manifest.
The other option is that the suit_storage_driver_t::erase is called. In this case the not-yet-installed payload must be erased again as its contents might not be what is expected by the digest in the manifest. The payload must then be removed to prevent the possibility of storing malicious code on the device.
A form of read access must be implemented to provide a way to read back the data and check the digest of the payload. suit_storage_driver_t::read must be implemented, providing piecewise reading of the data. suit_storage_driver_t::read_ptr is optional to implement, it can provide direct read access on memory-mapped storage.
As the storage backend provides a mechanism to store persistent data, functions are added to set and retrieve the manifest sequence number. While not strictly required to implement, a firmware without a mechanism to retrieve and store sequence numbers will always fail to update.
The suit_storage_driver_t::match_offset function allows the manifest handler to check the component-offset condition against a storage backend.
The usual call sequence by a manifest handler is:
- suit_storage_driver_t::init as on-boot initialization.
- suit_storage_driver_t::get_seq_no to determine if the manifest is not replayed.
- suit_storage_driver_t::has_location to determine if the backend handles the payload in the manifest.
- suit_storage_driver_t::set_active_location to set the active location for the payload.
- suit_storage_driver_t::start to start a payload write sequence.
- At least one suit_storage_driver_t::write calls to write the payload data.
- suit_storage_driver_t::finish to mark the end of the payload write.
- suit_storage_driver_t::read or suit_storage_driver_t::read_ptr to read back the written payload. This to verify the digest of the payload with what is provided in the manifest.
- suit_storage_driver_t::install if the digest matches with what is expected and the payload can be installed or marked as valid, or:
- suit_storage_driver_t::erase if the digest does not match with what is expected and must be erased.
- ref suit_storage_driver_t::set_seq_no to update the sequence number stored in the backend.
- Warning
- This API is by design not thread safe
|
For easy access to the suit_storage_driver_t functions.
|
static char | suit_storage_get_separator (const suit_storage_t *storage) |
| get the separator for a storage backend
|
|
static bool | suit_storage_has_readptr (const suit_storage_t *storage) |
| Check if the storage backend implements the suit_storage_driver_t::read_ptr function.
|
|
static bool | suit_storage_has_offset (const suit_storage_t *storage) |
| Check if the storage backend implements the suit_storage_driver_t::match_offset function.
|
|
static int | suit_storage_init (suit_storage_t *storage) |
| One-time initialization function.
|
|
static int | suit_storage_start (suit_storage_t *storage, const suit_manifest_t *manifest, size_t len) |
| Start a new payload write sequence.
|
|
static int | suit_storage_write (suit_storage_t *storage, const suit_manifest_t *manifest, const uint8_t *buf, size_t offset, size_t len) |
| Write a new chunk of the payload to the storage backend.
|
|
static int | suit_storage_finish (suit_storage_t *storage, const suit_manifest_t *manifest) |
| Signal that the payload write stage done to the storage backend.
|
|
static int | suit_storage_read (suit_storage_t *storage, uint8_t *buf, size_t offset, size_t len) |
| Read a chunk of previously written data back.
|
|
static int | suit_storage_read_ptr (suit_storage_t *storage, const uint8_t **buf, size_t *len) |
| retrieve a direct read pointer for this storage backend
|
|
static int | suit_storage_install (suit_storage_t *storage, const suit_manifest_t *manifest) |
| Install the payload or mark the payload as valid.
|
|
static int | suit_storage_erase (suit_storage_t *storage) |
| Erase the previously loaded payload.
|
|
static bool | suit_storage_has_location (suit_storage_t *storage, const char *location) |
| Check if this storage backend services a location.
|
|
static int | suit_storage_match_offset (const suit_storage_t *storage, size_t offset) |
| Checks if the supplied offset is true or false for the current location.
|
|
static int | suit_storage_set_active_location (suit_storage_t *storage, const char *location) |
| Set the active location of the storage handler.
|
|
static int | suit_storage_get_seq_no (const suit_storage_t *storage, uint32_t *seq_no) |
| Retrieve the sequence number from the storage backend.
|
|
static int | suit_storage_set_seq_no (suit_storage_t *storage, uint32_t seq_no) |
| Set a new sequence number in the storage backend.
|
|
◆ suit_storage_t
Forward declaration for storage struct.
Definition at line 110 of file storage.h.
◆ suit_storage_erase()
Erase the previously loaded payload.
- Parameters
-
[in] | storage | Storage context |
- Returns
- SUIT_OK on successfully erasing the data
-
suit_error_t on error
Definition at line 513 of file storage.h.
◆ suit_storage_find_by_component()
retrieve a storage backend based on the suit component
- Parameters
-
[in] | manifest | SUIT manifest context |
[in] | component | Component to find a storage backend for |
- Returns
- The first storage driver that handles this component
-
NULL if none of the storage drivers is able to handle this component.
◆ suit_storage_find_by_id()
retrieve a storage backend based on the location ID string
- Parameters
-
- Returns
- The first storage driver that handles this ID
-
NULL if none of the storage drivers is able to handle this ID.
◆ suit_storage_finish()
Signal that the payload write stage done to the storage backend.
- Parameters
-
[in] | storage | Storage context |
[in] | manifest | The suit manifest context |
- Returns
- SUIT_OK on successfully finalizing the write
-
suit_error_t on error
Definition at line 449 of file storage.h.
◆ suit_storage_get_highest_seq_no()
int suit_storage_get_highest_seq_no |
( |
uint32_t * |
seq_no | ) |
|
Get the highest sequence number among available backends.
- Parameters
-
[out] | seq_no | Retrieved sequence number |
- Returns
- suit_ok if at least one sequence number is retrieved
-
suit_error_t on error
◆ suit_storage_get_separator()
static char suit_storage_get_separator |
( |
const suit_storage_t * |
storage | ) |
|
|
inlinestatic |
get the separator for a storage backend
- Parameters
-
[in] | storage | Storage context |
- Returns
- The separator char
Definition at line 360 of file storage.h.
◆ suit_storage_get_seq_no()
static int suit_storage_get_seq_no |
( |
const suit_storage_t * |
storage, |
|
|
uint32_t * |
seq_no |
|
) |
| |
|
inlinestatic |
Retrieve the sequence number from the storage backend.
- Note
- The sequence number must be global to the storage context, it must not depend on the location
- Parameters
-
[in] | storage | Storage context |
[out] | seq_no | Retrieved sequence number |
- Returns
- SUIT_OK on success
-
suit_error_t if the sequence number can't be retrieved
Definition at line 588 of file storage.h.
◆ suit_storage_has_location()
static bool suit_storage_has_location |
( |
suit_storage_t * |
storage, |
|
|
const char * |
location |
|
) |
| |
|
inlinestatic |
Check if this storage backend services a location.
- Parameters
-
[in] | storage | Storage context |
[in] | location | Location to check |
- Returns
- True if this storage driver must be used for the supplied location
Definition at line 527 of file storage.h.
◆ suit_storage_has_offset()
◆ suit_storage_has_readptr()
static bool suit_storage_has_readptr |
( |
const suit_storage_t * |
storage | ) |
|
|
inlinestatic |
Check if the storage backend implements the suit_storage_driver_t::read_ptr function.
- Parameters
-
[in] | storage | Storage context |
- Returns
- True if the function is implemented,
-
False otherwise
Definition at line 374 of file storage.h.
◆ suit_storage_init()
One-time initialization function.
Called at boot.
- Parameters
-
[in] | storage | Storage context |
Definition at line 398 of file storage.h.
◆ suit_storage_install()
Install the payload or mark the payload as valid.
- Parameters
-
[in] | storage | Storage context |
[in] | manifest | The suit manifest context |
- Returns
- SUIT_OK on successfully installing the payload
-
suit_error_t on error
Definition at line 499 of file storage.h.
◆ suit_storage_match_offset()
static int suit_storage_match_offset |
( |
const suit_storage_t * |
storage, |
|
|
size_t |
offset |
|
) |
| |
|
inlinestatic |
Checks if the supplied offset is true or false for the current location.
- Note
- Optional to implement, should not be implemented if the backend doesn't support the image_offset
- Parameters
-
[in] | storage | Storage context |
[in] | offset | Offset to check |
- Returns
- True if the location matches the offset,
-
False otherwise
Definition at line 546 of file storage.h.
◆ suit_storage_read()
static int suit_storage_read |
( |
suit_storage_t * |
storage, |
|
|
uint8_t * |
buf, |
|
|
size_t |
offset, |
|
|
size_t |
len |
|
) |
| |
|
inlinestatic |
Read a chunk of previously written data back.
- Parameters
-
[in] | storage | Storage context |
[out] | buf | Buffer to write the read data in |
[in] | offset | Offset to read from |
[in] | len | Number of bytes to read |
- Returns
- SUIT_OK on successfully reading the chunk
-
suit_error_t on error
Definition at line 466 of file storage.h.
◆ suit_storage_read_ptr()
static int suit_storage_read_ptr |
( |
suit_storage_t * |
storage, |
|
|
const uint8_t ** |
buf, |
|
|
size_t * |
len |
|
) |
| |
|
inlinestatic |
retrieve a direct read pointer for this storage backend
- Note
- Optional to implement
- Parameters
-
[in] | storage | Storage context |
[out] | buf | Pointer to the location data |
[out] | len | Full length of the location data |
- Returns
- SUIT_OK on successfully providing the region
-
suit_error_t on error
Definition at line 484 of file storage.h.
◆ suit_storage_set_active_location()
static int suit_storage_set_active_location |
( |
suit_storage_t * |
storage, |
|
|
const char * |
location |
|
) |
| |
|
inlinestatic |
Set the active location of the storage handler.
A storage backend can handle multiple locations, e.g. a VFS backend targeting multiple files on a filesystem, setting the location selects the target location for writes or reads.
- Note
- Must be idempotent
- Parameters
-
- Returns
- SUIT_OK on success
-
SUIT_ERR_STORAGE_UNAVAILABLE if the location is not available.
Definition at line 570 of file storage.h.
◆ suit_storage_set_seq_no()
static int suit_storage_set_seq_no |
( |
suit_storage_t * |
storage, |
|
|
uint32_t |
seq_no |
|
) |
| |
|
inlinestatic |
Set a new sequence number in the storage backend.
- Parameters
-
[in] | storage | Storage context |
[in] | seq_no | Sequence number to store |
- Returns
- SUIT_OK on success
-
suit_error_t if the sequence number can't be stored.
Definition at line 603 of file storage.h.
◆ suit_storage_set_seq_no_all()
int suit_storage_set_seq_no_all |
( |
uint32_t |
seq_no | ) |
|
Set the new sequence number on all available backends.
- Parameters
-
[in] | seq_no | Sequence number to store |
- Returns
- SUIT_OK on successfully storing the sequence number on at least one backend
-
suit_error_t on error
◆ suit_storage_start()
Start a new payload write sequence.
- Parameters
-
[in] | storage | Storage context |
[in] | manifest | The suit manifest context |
[in] | len | Total size of the payload in bytes |
- Returns
- SUIT_OK on successfully starting the write
-
suit_error_t on error
Definition at line 413 of file storage.h.
◆ suit_storage_write()
Write a new chunk of the payload to the storage backend.
- Parameters
-
[in] | storage | Storage context |
[in] | manifest | The suit manifest context |
[in] | buf | Buffer to read the payload chunk from |
[in] | offset | Offset to write at |
[in] | len | Length of the payload chunk |
- Returns
- SUIT_OK on successfully writing the chunk
-
suit_error_t on error
Definition at line 432 of file storage.h.