1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/suit/storage/flashwrite.c
2022-06-03 08:49:43 +02:00

247 lines
6.8 KiB
C

/*
* 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 <koen@bergzand.net>
*
* @}
*/
#include <string.h>
#include "kernel_defines.h"
#include "log.h"
#include "xfa.h"
#include "suit.h"
#include "suit/storage.h"
#include "suit/storage/flashwrite.h"
#include "riotboot/flashwrite.h"
#include "riotboot/slot.h"
XFA_USE(suit_storage_t, suit_storage_reg);
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;
LOG_DEBUG("Storage size %u\n", (unsigned)sizeof(suit_storage_flashwrite_t));
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)
{
suit_storage_flashwrite_t *fw = _get_fw(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 CONFIG_RIOTBOOT_FLASHWRITE_RAW
/* Insert the first chunk from the separate buffer here, there are cases
* where the chunk size is 4 bytes and we can skip this because it only
* contains the magic number already copied above. */
if (offset < RIOTBOOT_FLASHPAGE_BUFFER_SIZE) {
const size_t chunk_remaining =
RIOTBOOT_FLASHPAGE_BUFFER_SIZE - _prefix_len;
/* How much of the first page must be copied */
size_t firstpage_to_copy = len > chunk_remaining ?
(chunk_remaining) : len;
/* Copy the first buffer */
memcpy(buf, fw->writer.firstblock_buf + offset, firstpage_to_copy);
offset += firstpage_to_copy;
buf += firstpage_to_copy;
len -= firstpage_to_copy;
}
#else
(void)fw;
#endif /* CONFIG_RIOTBOOT_FLASHWRITE_RAW */
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 = (uintptr_t)riotboot_slot_offset(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',
};
static suit_storage_flashwrite_t suit_storage_flashwrite = {
.storage = {
.driver = &suit_storage_flashwrite_driver,
},
};
XFA(suit_storage_reg, 0) suit_storage_t* suit_storage_flashwrite_ptr = &suit_storage_flashwrite.storage;