diff --git a/sys/include/suit/storage/flashwrite.h b/sys/include/suit/storage/flashwrite.h new file mode 100644 index 0000000000..354d0db03f --- /dev/null +++ b/sys/include/suit/storage/flashwrite.h @@ -0,0 +1,43 @@ +/* + * 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_flashwrite riotboot flashwrite storage backend + * @ingroup sys_suit_storage + * @brief SUIT riotboot firmware storage backend + * + * @{ + * + * @brief riotboot Flashwrite storage backend functions for SUIT manifests + * @author Koen Zandberg + */ + +#ifndef SUIT_STORAGE_FLASHWRITE_H +#define SUIT_STORAGE_FLASHWRITE_H + +#include "suit.h" +#include "riotboot/flashwrite.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief riotboot flashwrite SUIT storage context + */ +typedef struct { + suit_storage_t storage; /**< parent struct */ + riotboot_flashwrite_t writer; /**< Riotboot flashwriter */ +} suit_storage_flashwrite_t; + +#ifdef __cplusplus +} +#endif + +#endif /* SUIT_STORAGE_FLASHWRITE_H */ +/** @} */ diff --git a/sys/suit/storage/flashwrite.c b/sys/suit/storage/flashwrite.c new file mode 100644 index 0000000000..c32c57f9ce --- /dev/null +++ b/sys/suit/storage/flashwrite.c @@ -0,0 +1,216 @@ +/* + * 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 flashwrite storage module implementation + * + * @author Koen Zandberg + * + * @} + */ +#include + +#include "kernel_defines.h" +#include "log.h" + +#include "suit.h" +#include "suit/storage.h" +#include "suit/storage/flashwrite.h" +#include "riotboot/flashwrite.h" +#include "riotboot/slot.h" + +static inline suit_storage_flashwrite_t *_get_fw(suit_storage_t *storage) +{ + return container_of(storage, suit_storage_flashwrite_t, storage); +} + +static int _flashwrite_init(suit_storage_t *storage) +{ + (void)storage; + return 0; +} + +static int _flashwrite_start(suit_storage_t *storage, + const suit_manifest_t *manifest, + size_t len) +{ + (void)manifest; + (void)len; + suit_storage_flashwrite_t *fw = _get_fw(storage); + int target_slot = riotboot_slot_other(); + + return riotboot_flashwrite_init(&fw->writer, target_slot); +} + +static int _flashwrite_write(suit_storage_t *storage, + const suit_manifest_t *manifest, + const uint8_t *buf, size_t offset, size_t len) +{ + (void)manifest; + suit_storage_flashwrite_t *fw = _get_fw(storage); + + if (offset == 0) { + if (len < RIOTBOOT_FLASHWRITE_SKIPLEN) { + LOG_WARNING("_suit_flashwrite(): offset==0, len<4. aborting\n"); + return -1; + } + offset = RIOTBOOT_FLASHWRITE_SKIPLEN; + buf += RIOTBOOT_FLASHWRITE_SKIPLEN; + len -= RIOTBOOT_FLASHWRITE_SKIPLEN; + } + + if (offset != fw->writer.offset) { + LOG_ERROR("Unexpected offset: %u - expected: %u\n", (unsigned)offset, + (unsigned)fw->writer.offset); + return SUIT_ERR_STORAGE; + } + + return riotboot_flashwrite_putbytes(&fw->writer, buf, len, 1); +} + +static int _flashwrite_finish(suit_storage_t *storage, + const suit_manifest_t *manifest) +{ + (void)manifest; + suit_storage_flashwrite_t *fw = _get_fw(storage); + + return riotboot_flashwrite_flush(&fw->writer) < + 0 ? SUIT_ERR_STORAGE : SUIT_OK; +} + +static int _flashwrite_install(suit_storage_t *storage, + const suit_manifest_t *manifest) +{ + (void)manifest; + suit_storage_flashwrite_t *fw = _get_fw(storage); + + return riotboot_flashwrite_finish(&fw->writer); +} + +static int _flashwrite_read(suit_storage_t *storage, uint8_t *buf, + size_t offset, size_t len) +{ + (void)storage; + + static const char _prefix[] = "RIOT"; + static const size_t _prefix_len = sizeof(_prefix) - 1; + int target_slot = riotboot_slot_other(); + size_t slot_size = riotboot_slot_size(target_slot); + + /* Insert the "RIOT" magic number */ + if (offset < (_prefix_len)) { + size_t prefix_to_copy = _prefix_len - offset; + memcpy(buf, _prefix + offset, prefix_to_copy); + len -= prefix_to_copy; + offset = _prefix_len; + buf += prefix_to_copy; + + } + if (offset + len > slot_size) { + return -1; + } + + uint8_t *slot = (uint8_t *)riotboot_slot_get_hdr(target_slot); + + memcpy(buf, slot + offset, len); + return 0; +} + +static bool _flashwrite_has_location(const suit_storage_t *storage, + const char *location) +{ + (void)storage; + + /* Firmware matches at zero length string */ + return (location[0] == '\0'); +} + +static int _flashwrite_set_active_location(suit_storage_t *storage, + const char *location) +{ + (void)storage; + (void)location; + return 0; +} + +static bool _flashwrite_match_offset(const suit_storage_t *storage, + size_t offset) +{ + (void)storage; + + int target_slot = riotboot_slot_other(); + uintptr_t slot_start = (intptr_t)riotboot_slot_get_hdr(target_slot); + + return (slot_start == (uintptr_t)offset); +} + +static int _flashwrite_get_seq_no(const suit_storage_t *storage, + uint32_t *seq_no) +{ + (void)storage; + uint32_t max_seq_no = 0; + bool valid = false; + + for (unsigned i = 0; i < riotboot_slot_numof; i++) { + const riotboot_hdr_t *riot_hdr = riotboot_slot_get_hdr(i); + if (riotboot_slot_validate(i)) { + /* skip slot if metadata broken */ + continue; + } + if (!valid || riot_hdr->version > max_seq_no) { + max_seq_no = riot_hdr->version; + valid = true; + } + } + if (valid) { + *seq_no = max_seq_no; + return SUIT_OK; + } + + return -1; +} + +static int _flashwrite_set_seq_no(suit_storage_t *storage, + uint32_t seq_no) +{ + (void)storage; + int target_slot = riotboot_slot_other(); + const riotboot_hdr_t *hdr = riotboot_slot_get_hdr(target_slot); + + if (hdr->version == seq_no) { + return SUIT_OK; + } + + return -1; +} + +static const suit_storage_driver_t suit_storage_flashwrite_driver = { + .init = _flashwrite_init, + .start = _flashwrite_start, + .write = _flashwrite_write, + .finish = _flashwrite_finish, + .read = _flashwrite_read, + .install = _flashwrite_install, + .has_location = _flashwrite_has_location, + .set_active_location = _flashwrite_set_active_location, + .match_offset = _flashwrite_match_offset, + .get_seq_no = _flashwrite_get_seq_no, + .set_seq_no = _flashwrite_set_seq_no, + .separator = '\0', +}; + +suit_storage_flashwrite_t suit_storage_flashwrite = { + .storage = { + .driver = &suit_storage_flashwrite_driver, + }, +};