From 9ce2ba1c556234f19c96e39123d57c6a78d16498 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Mon, 28 Sep 2020 23:05:29 +0200 Subject: [PATCH] suit/storage/ram: Introduce RAM storage backend for SUIT --- sys/include/suit/storage/ram.h | 89 +++++++++++++ sys/suit/storage/ram.c | 231 +++++++++++++++++++++++++++++++++ 2 files changed, 320 insertions(+) create mode 100644 sys/include/suit/storage/ram.h create mode 100644 sys/suit/storage/ram.c diff --git a/sys/include/suit/storage/ram.h b/sys/include/suit/storage/ram.h new file mode 100644 index 0000000000..2320648a47 --- /dev/null +++ b/sys/include/suit/storage/ram.h @@ -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 + * + * 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 + +#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 */ +/** @} */ diff --git a/sys/suit/storage/ram.c b/sys/suit/storage/ram.c new file mode 100644 index 0000000000..773fce98d2 --- /dev/null +++ b/sys/suit/storage/ram.c @@ -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 + * + * @} + */ +#include +#include + +#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(®ion->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, ®ion->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, ®ion)) { + 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, + }, +};