suit/storage/ram: Introduce RAM storage backend for SUIT

This commit is contained in:
Koen Zandberg 2020-09-28 23:05:29 +02:00
parent 7742750abd
commit 9ce2ba1c55
No known key found for this signature in database
GPG Key ID: 0895A893E6D2985B
2 changed files with 320 additions and 0 deletions

View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2020 Koen Zandberg
* 2020 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.
*/
/**
* @defgroup sys_suit_storage_ram ram storage backend
* @ingroup sys_suit_storage
* @brief RAM blob SUIT payload storage backends
*
* @{
*
* @brief RAM-based storage backend for SUIT OTA updates
* @author Koen Zandberg <koen@bergzand.net>
*
* This module implements a RAM-backed storage interface for SUIT. The main
* purpose is mock testing the SUIT implementation, however the interface could
* also be used for to target backup ram storage by changing @ref
* CONFIG_SUIT_STORAGE_RAM_SIZE to store it in backup ram.
*
* The module uses a .ram.### structure where the number indicates the index of
* the memory region being targeted.
*
* @warning The install function is implemented as a noop. There is no
* distinction between valid content and not yet invalidated content.
*/
#ifndef SUIT_STORAGE_RAM_H
#define SUIT_STORAGE_RAM_H
#include <stdint.h>
#include "suit.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Size of each memory region
*/
#ifndef CONFIG_SUIT_STORAGE_RAM_SIZE
#define CONFIG_SUIT_STORAGE_RAM_SIZE (64U)
#endif
/**
* @brief Number of allocated regions
*/
#ifndef CONFIG_SUIT_STORAGE_RAM_REGIONS
#define CONFIG_SUIT_STORAGE_RAM_REGIONS (2U)
#endif
/**
* @brief Extra attributes for allocating the RAM struct
*/
#ifndef CONFIG_SUIT_STORAGE_RAM_ATTR
#define CONFIG_SUIT_STORAGE_RAM_ATTR
#endif
/**
* @brief Single in-memory storage region
*/
typedef struct {
size_t occupied; /**< Region space filled */
uint8_t mem[CONFIG_SUIT_STORAGE_RAM_SIZE]; /**< RAM area */
} suit_storage_ram_region_t;
/**
* @brief memory storage state
*/
typedef struct CONFIG_SUIT_STORAGE_RAM_ATTR {
suit_storage_t storage; /**< parent struct */
/**
* @brief ram storage regions
*/
suit_storage_ram_region_t regions[CONFIG_SUIT_STORAGE_RAM_REGIONS];
size_t active_region; /**< Active region to write to */
uint32_t sequence_no; /**< Ephemeral sequence number */
} suit_storage_ram_t;
#ifdef __cplusplus
}
#endif
#endif /* SUIT_STORAGE_RAM_H */
/** @} */

231
sys/suit/storage/ram.c Normal file
View File

@ -0,0 +1,231 @@
/*
* Copyright (C) 2020 Koen Zandberg
* 2020 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 sys_suit_storage
* @{
*
* @file
* @brief SUIT ram storage module implementation
*
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/
#include <string.h>
#include <inttypes.h>
#include "fmt.h"
#include "kernel_defines.h"
#include "log.h"
#include "suit.h"
#include "suit/storage.h"
#include "suit/storage/ram.h"
static inline suit_storage_ram_t *_get_ram(suit_storage_t *storage)
{
return container_of(storage, suit_storage_ram_t, storage);
}
static inline const suit_storage_ram_t *_get_ram_const(
const suit_storage_t *storage)
{
return container_of(storage, suit_storage_ram_t, storage);
}
static inline suit_storage_ram_region_t *_get_active_region(
suit_storage_ram_t *ram)
{
return &ram->regions[ram->active_region];
}
static bool _get_region_by_string(const char *location, uint32_t *val)
{
/* Matching on .ram.### */
static const char prefix[] = ".ram.";
static const size_t prefix_len = sizeof(prefix) - 1;
/* Check for prefix */
if (strncmp(prefix, location, prefix_len) == 0 &&
location[prefix_len] != '\n') {
/* Advance to the number */
location += prefix_len;
/* Check if the rest of the string is a number */
if (fmt_is_number(location)) {
/* grab the number */
*val = scn_u32_dec(location, 5);
/* Number must be smaller than the number of regions */
if (*val < CONFIG_SUIT_STORAGE_RAM_REGIONS) {
return true;
}
}
}
return false;
}
static int _ram_init(suit_storage_t *storage)
{
suit_storage_ram_t *ram = _get_ram(storage);
/* Clear the ram regions */
memset(ram->regions, 0,
sizeof(suit_storage_ram_region_t) * CONFIG_SUIT_STORAGE_RAM_REGIONS);
return SUIT_OK;
}
static int _ram_start(suit_storage_t *storage, const suit_manifest_t *manifest,
size_t len)
{
(void)manifest;
suit_storage_ram_t *ram = _get_ram(storage);
suit_storage_ram_region_t *region = _get_active_region(ram);
if (len > CONFIG_SUIT_STORAGE_RAM_SIZE) {
return SUIT_ERR_STORAGE_EXCEEDED;
}
region->occupied = 0;
return SUIT_OK;
}
static int _ram_write(suit_storage_t *storage, const suit_manifest_t *manifest,
const uint8_t *buf, size_t offset, size_t len)
{
(void)manifest;
suit_storage_ram_t *ram = _get_ram(storage);
suit_storage_ram_region_t *region = _get_active_region(ram);
if (offset + len > CONFIG_SUIT_STORAGE_RAM_SIZE) {
return SUIT_ERR_STORAGE_EXCEEDED;
}
memcpy(&region->mem[offset], buf, len);
region->occupied += len;
return SUIT_OK;
}
static int _ram_finish(suit_storage_t *storage, const suit_manifest_t *manifest)
{
(void)storage;
(void)manifest;
return SUIT_OK;
}
static int _ram_install(suit_storage_t *storage,
const suit_manifest_t *manifest)
{
(void)manifest;
(void)storage;
return SUIT_OK;
}
static int _ram_erase(suit_storage_t *storage)
{
suit_storage_ram_t *ram = _get_ram(storage);
suit_storage_ram_region_t *region = _get_active_region(ram);
memset(region->mem, 0, CONFIG_SUIT_STORAGE_RAM_SIZE);
return SUIT_OK;
}
static int _ram_read(suit_storage_t *storage, uint8_t *buf, size_t offset,
size_t len)
{
suit_storage_ram_t *ram = _get_ram(storage);
suit_storage_ram_region_t *region = _get_active_region(ram);
if (offset + len > CONFIG_SUIT_STORAGE_RAM_SIZE) {
return SUIT_ERR_STORAGE_EXCEEDED;
}
memcpy(buf, &region->mem[offset], len);
return SUIT_OK;
}
static int _ram_read_ptr(suit_storage_t *storage,
const uint8_t **buf, size_t *len)
{
suit_storage_ram_t *ram = _get_ram(storage);
suit_storage_ram_region_t *region = _get_active_region(ram);
*buf = region->mem;
*len = region->occupied;
return SUIT_OK;
}
static bool _ram_has_location(const suit_storage_t *storage,
const char *location)
{
(void)storage;
uint32_t val;
return _get_region_by_string(location, &val);
}
static int _ram_set_active_location(suit_storage_t *storage,
const char *location)
{
suit_storage_ram_t *ram = _get_ram(storage);
uint32_t region = 0;
if (!_get_region_by_string(location, &region)) {
return -1;
}
ram->active_region = region;
return SUIT_OK;
}
static int _ram_get_seq_no(const suit_storage_t *storage, uint32_t *seq_no)
{
const suit_storage_ram_t *ram = _get_ram_const(storage);
*seq_no = ram->sequence_no;
LOG_INFO("Retrieved sequence number: %" PRIu32 "\n", *seq_no);
return SUIT_OK;
}
static int _ram_set_seq_no(suit_storage_t *storage, uint32_t seq_no)
{
suit_storage_ram_t *ram = _get_ram(storage);
if (ram->sequence_no < seq_no) {
LOG_INFO("Stored sequence number: %" PRIu32 "\n", seq_no);
ram->sequence_no = seq_no;
return SUIT_OK;
}
return SUIT_ERR_SEQUENCE_NUMBER;
}
static const suit_storage_driver_t suit_storage_ram_driver = {
.init = _ram_init,
.start = _ram_start,
.write = _ram_write,
.finish = _ram_finish,
.read = _ram_read,
.read_ptr = _ram_read_ptr,
.install = _ram_install,
.erase = _ram_erase,
.has_location = _ram_has_location,
.set_active_location = _ram_set_active_location,
.get_seq_no = _ram_get_seq_no,
.set_seq_no = _ram_set_seq_no,
.separator = '.',
};
suit_storage_ram_t suit_storage_ram = {
.storage = {
.driver = &suit_storage_ram_driver,
},
};