1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

riotboot/flashwrite: add flashpage_raw compatibility

This adds optional usage of periph_flashpage_raw for the
riotboot/flashwrite module. This removes the need to buffer a full
flashpage page, instead it must buffer two times the
FLASHPAGE_RAW_BLOCKSIZE. One is used to buffer the current write block,
the other buffers the first chunk (offset zero, page zero). This first
chunk is written when finalizing the flash operation.

Care must be taken that, when using the skiplength, the number of bytes
skipped is always a multiple of the FLASHPAGE_RAW_BLOCKSIZE.
This commit is contained in:
Koen Zandberg 2020-10-01 19:05:09 +02:00
parent 90cd436c1d
commit 55b0f0b6a8
No known key found for this signature in database
GPG Key ID: 0895A893E6D2985B
3 changed files with 122 additions and 8 deletions

View File

@ -892,6 +892,7 @@ endif
ifneq (,$(filter riotboot_flashwrite, $(USEMODULE)))
USEMODULE += riotboot_slot
FEATURES_REQUIRED += periph_flashpage
FEATURES_OPTIONAL += periph_flashpage_raw
endif
ifneq (,$(filter riotboot_slot, $(USEMODULE)))

View File

@ -41,6 +41,15 @@
* 2. write image starting at second block
* 3. write first block
*
* When using periph_flashpage_raw with this module, the need to buffer a full
* flashpage page is removed, instead it must buffer two times the
* FLASHPAGE_RAW_BLOCKSIZE. One is used to buffer the current write block,
* the other buffers the first chunk (offset zero, page zero). This first
* chunk is written when finalizing the flash operation. The minimal size for
* RIOTBOOT_FLASHPAGE_BUFFER_SIZE is 4, at least the riotboot magic number must
* fit into this and FLASHPAGE_SIZE must be a multiple of
* RIOTBOOT_FLASHPAGE_BUFFER_SIZE
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Koen Zandberg <koen@bergzand.net>
*
@ -57,6 +66,36 @@ extern "C" {
#include "riotboot/slot.h"
#include "periph/flashpage.h"
/**
* @brief Enable/disable raw writes to flash
*/
#ifndef CONFIG_RIOTBOOT_FLASHWRITE_RAW
#define CONFIG_RIOTBOOT_FLASHWRITE_RAW IS_ACTIVE(MODULE_PERIPH_FLASHPAGE_RAW)
#endif
/**
* @brief Intermediate buffer size for firmware image data
*/
#if CONFIG_RIOTBOOT_FLASHWRITE_RAW
#if (FLASHPAGE_RAW_BLOCKSIZE < 4)
#define RIOTBOOT_FLASHPAGE_BUFFER_SIZE 4
#else
#define RIOTBOOT_FLASHPAGE_BUFFER_SIZE FLASHPAGE_RAW_BLOCKSIZE
#endif
#else /* CONFIG_RIOTBOOT_FLASHWRITE_RAW */
#define RIOTBOOT_FLASHPAGE_BUFFER_SIZE FLASHPAGE_SIZE
#endif /* !CONFIG_RIOTBOOT_FLASHWRITE_RAW */
/**
* @brief Extra attributes required for the firmware intermediate buffer
*/
#define RIOTBOOT_FLASHPAGE_BUFFER_ATTRS \
__attribute__((aligned(FLASHPAGE_RAW_ALIGNMENT)))
/**
* @brief firmware update state structure
*
@ -67,7 +106,20 @@ typedef struct {
int target_slot; /**< update targets this slot */
size_t offset; /**< update is at this position */
unsigned flashpage; /**< update is at this flashpage */
uint8_t flashpage_buf[FLASHPAGE_SIZE]; /**< flash writing buffer */
/**
* @brief flash writing buffer
*/
uint8_t RIOTBOOT_FLASHPAGE_BUFFER_ATTRS
flashpage_buf[RIOTBOOT_FLASHPAGE_BUFFER_SIZE];
#if CONFIG_RIOTBOOT_FLASHWRITE_RAW || DOXYGEN
/**
* @brief Buffer for the first chunk containing the checksum when using
* FLASHWRITE_RAW
*/
uint8_t RIOTBOOT_FLASHPAGE_BUFFER_ATTRS
firstblock_buf[RIOTBOOT_FLASHPAGE_BUFFER_SIZE];
#endif
} riotboot_flashwrite_t;
/**

View File

@ -44,6 +44,8 @@ int riotboot_flashwrite_init_raw(riotboot_flashwrite_t *state, int target_slot,
size_t offset)
{
assert(offset <= FLASHPAGE_SIZE);
/* the flashpage size must be a multiple of the riotboot flashpage buffer */
static_assert(!(FLASHPAGE_SIZE % RIOTBOOT_FLASHPAGE_BUFFER_SIZE));
LOG_INFO(LOG_PREFIX "initializing update to target slot %i\n",
target_slot);
@ -54,14 +56,37 @@ int riotboot_flashwrite_init_raw(riotboot_flashwrite_t *state, int target_slot,
state->target_slot = target_slot;
state->flashpage = flashpage_page((void *)riotboot_slot_get_hdr(target_slot));
if (CONFIG_RIOTBOOT_FLASHWRITE_RAW && offset) {
/* Erase the first page only if the offset (!=0) specifies that there is
* a checksum or other mechanism at the start of the page. */
flashpage_write(state->flashpage, NULL);
}
return 0;
}
int riotboot_flashwrite_flush(riotboot_flashwrite_t *state)
{
if (flashpage_write_and_verify(state->flashpage, state->flashpage_buf) != FLASHPAGE_OK) {
LOG_WARNING(LOG_PREFIX "error writing flashpage %u!\n", state->flashpage);
return -1;
if (CONFIG_RIOTBOOT_FLASHWRITE_RAW) {
/* Check if there is leftover data in the buffer */
size_t flashwrite_buffer_pos = state->offset % RIOTBOOT_FLASHPAGE_BUFFER_SIZE;
if (flashwrite_buffer_pos == 0) {
return 0;
}
uint8_t* slot_start =
(uint8_t*)riotboot_slot_get_hdr(state->target_slot);
/* Get the offset of the remaining chunk */
size_t flashpage_pos = state->offset - flashwrite_buffer_pos;
/* Write remaining chunk */
flashpage_write_raw(slot_start + flashpage_pos,
state->flashpage_buf,
RIOTBOOT_FLASHPAGE_BUFFER_SIZE);
}
else {
if (flashpage_write_and_verify(state->flashpage, state->flashpage_buf) != FLASHPAGE_OK) {
LOG_WARNING(LOG_PREFIX "error writing flashpage %u!\n", state->flashpage);
return -1;
}
}
return 0;
}
@ -73,22 +98,52 @@ int riotboot_flashwrite_putbytes(riotboot_flashwrite_t *state,
while (len) {
size_t flashpage_pos = state->offset % FLASHPAGE_SIZE;
size_t flashpage_avail = FLASHPAGE_SIZE - flashpage_pos;
size_t flashwrite_buffer_pos = state->offset % RIOTBOOT_FLASHPAGE_BUFFER_SIZE;
size_t flashpage_avail = RIOTBOOT_FLASHPAGE_BUFFER_SIZE - flashwrite_buffer_pos;
size_t to_copy = min(flashpage_avail, len);
memcpy(state->flashpage_buf + flashpage_pos, bytes, to_copy);
if (CONFIG_RIOTBOOT_FLASHWRITE_RAW && flashpage_pos == 0) {
/* Erase the next page */
state->flashpage++;
flashpage_write(state->flashpage, NULL);
}
if (CONFIG_RIOTBOOT_FLASHWRITE_RAW &&
flashwrite_buffer_pos == 0) {
memset(state->flashpage_buf, 0, RIOTBOOT_FLASHPAGE_BUFFER_SIZE);
};
memcpy(state->flashpage_buf + flashwrite_buffer_pos, bytes, to_copy);
flashpage_avail -= to_copy;
state->offset += to_copy;
bytes += to_copy;
len -= to_copy;
if ((!flashpage_avail) || (!more)) {
if (flashpage_write_and_verify(state->flashpage, state->flashpage_buf) != FLASHPAGE_OK) {
#if CONFIG_RIOTBOOT_FLASHWRITE_RAW /* Guards access to state::firstblock_buf */
void * addr = flashpage_addr(state->flashpage);
if (addr == riotboot_slot_get_hdr(state->target_slot) &&
state->offset == RIOTBOOT_FLASHPAGE_BUFFER_SIZE) {
/* Skip flashing the first block, store it for later to flash it
* during the flashwrite_finish function */
memcpy(state->firstblock_buf,
state->flashpage_buf, RIOTBOOT_FLASHPAGE_BUFFER_SIZE);
}
else {
flashpage_write_raw((uint8_t*)addr + flashpage_pos,
state->flashpage_buf,
RIOTBOOT_FLASHPAGE_BUFFER_SIZE);
}
#else
int res = flashpage_write_and_verify(state->flashpage,
state->flashpage_buf);
if (res != FLASHPAGE_OK) {
LOG_WARNING(LOG_PREFIX "error writing flashpage %u!\n", state->flashpage);
return -1;
}
state->flashpage++;
#endif
}
}
@ -104,6 +159,10 @@ int riotboot_flashwrite_finish_raw(riotboot_flashwrite_t *state,
uint8_t *slot_start = (uint8_t *)riotboot_slot_get_hdr(state->target_slot);
#if CONFIG_RIOTBOOT_FLASHWRITE_RAW
memcpy(state->firstblock_buf, bytes, len);
flashpage_write_raw(slot_start, state->firstblock_buf, RIOTBOOT_FLASHPAGE_BUFFER_SIZE);
#else
uint8_t *firstpage;
if (len < FLASHPAGE_SIZE) {
@ -122,10 +181,12 @@ int riotboot_flashwrite_finish_raw(riotboot_flashwrite_t *state,
LOG_WARNING(LOG_PREFIX "re-flashing first block failed!\n");
goto out;
}
#endif /* !CONFIG_RIOTBOOT_FLASHWRITE_RAW */
LOG_INFO(LOG_PREFIX "riotboot flashing completed successfully\n");
res = 0;
#if !CONFIG_RIOTBOOT_FLASHWRITE_RAW
out:
#endif
return res;
}