1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/sys/include/riotboot/flashwrite.h
Kaspar Schleiser 0f5a2b4795 sys/riotboot: add initial image digest verification
Co-authored-by: Alexandre Abadie <alexandre.abadie@inria.fr>
2019-07-10 13:15:02 +02:00

191 lines
6.3 KiB
C

/*
* Copyright (C) 2018 Kaspar Schleiser <kaspar@schleiser.de>
* 2018 Inria
* 2018 Freie Universität Berlin
*
* 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_riotboot_flashwrite riotboot flash writer
* @ingroup sys
* @{
*
* @file
* @brief riotboot flash writing module
*
* This module provides an API to reliably write a firmware image to flash.
*
* The API is similar to stream hashing functions:
*
* 1. initialize state structure using riotboot_flashwrite_init()
* 2. put some data using riotboot_flashwrite_putbytes()
* 3. repeat 2. until all data has been received
* 4. finish update using riotboot_flashwrite_finish()
*
* The module will *not* automatically reboot after an image has been
* successfully written.
*
* Under the hood, the module tries to abstract page sizes for writing the image
* to flash. Verification of the image is left to the caller.
* If the data is not correctly written, riotboot_put_bytes() will
* return -1.
*
* The module makes sure that at no point in time an invalid image is bootable.
* The algorithm for that makes use of the bootloader verifying checksum and
* works as follows:
*
* 1. erase first block (making its checksum invalid)
* 2. write image starting at second block
* 3. write first block
*
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @author Koen Zandberg <koen@bergzand.net>
*
* @}
*/
#ifndef RIOTBOOT_FLASHWRITE_H
#define RIOTBOOT_FLASHWRITE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "riotboot/slot.h"
#include "periph/flashpage.h"
/**
* @brief firmware update state structure
*/
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 */
} riotboot_flashwrite_t;
/**
* @brief Amount of bytes to skip at initial write of first page
*/
#define RIOTBOOT_FLASHWRITE_SKIPLEN sizeof(RIOTBOOT_MAGIC)
/**
* @brief Initialize firmware update (raw version)
*
* Allows setting the initial offset to @p offset, which would mean that the
* first bytes passed in via @ref riotboot_flashwrite_putbytes() will be
* written to (slot_start + offset).
*
* @note offset *should* be <= FLASHPAGE_SIZE, otherwise the results are
* undefined.
*
* @param[in,out] state ptr to preallocated state structure
* @param[in] target_slot slot to write update into
* @param[in] offset Bytes offset to start write at
*
* @returns 0 on success, <0 otherwise
*/
int riotboot_flashwrite_init_raw(riotboot_flashwrite_t *state, int target_slot,
size_t offset);
/**
* @brief Initialize firmware update (riotboot version)
*
* This function initializes a firmware update, skipping riotboot's magic
* number ("RIOT") by calling @ref riotboot_flashwrite_init_raw() with an
* offset of RIOTBOOT_FLASHWRITE_SKIPLEN (4). This ensures that riotboot will
* ignore the slot until the magic number has been restored, e.g., through @ref
* riotboot_flashwrite_finish().
*
* @param[in,out] state ptr to preallocated state structure
* @param[in] target_slot slot to write update into
*
* @returns 0 on success, <0 otherwise
*/
static inline int riotboot_flashwrite_init(riotboot_flashwrite_t *state,
int target_slot)
{
/* initialize state, but skip "RIOT" */
return riotboot_flashwrite_init_raw(state, target_slot,
RIOTBOOT_FLASHWRITE_SKIPLEN);
}
/**
* @brief Feed bytes into the firmware writer
*
* @note If the update has been initialized via @ref
* riotboot_flashwrite_init(), make sure to skip the first
* RIOTBOOT_FLASHWRITE_SKIPLEN bytes.
*
* @param[in,out] state ptr to previously used update state
* @param[in] bytes ptr to data
* @param[in] len len of data
* @param[in] more whether more data is coming
*
* @returns 0 on success, <0 otherwise
*/
int riotboot_flashwrite_putbytes(riotboot_flashwrite_t *state,
const uint8_t *bytes, size_t len, bool more);
/**
* @brief Finish a firmware update (raw version)
*
* This function finishes a firmware update by re-writing the first header
*
* @param[in] state ptr to previously used state structure
* @param[in] bytes data to re-write in the first page
* @param[in] len size of data in bytes (must be <=FLASHPAGE_SIZE)
*
* @returns 0 on success, <0 otherwise
*/
int riotboot_flashwrite_finish_raw(riotboot_flashwrite_t *state,
const uint8_t *bytes, size_t len);
/**
* @brief Finish a firmware update (riotboot version)
*
* This function finishes a firmware update by re-writing the first header so
* it includes riotboot's magic number ("RIOT").
*
* @param[in] state ptr to previously used state structure
*
* @returns 0 on success, <0 otherwise
*/
static inline int riotboot_flashwrite_finish(riotboot_flashwrite_t *state)
{
return riotboot_flashwrite_finish_raw(state, (const uint8_t *)"RIOT",
RIOTBOOT_FLASHWRITE_SKIPLEN);
}
/**
* @brief Get a slot's size
*
* @param[in] state ptr to state struct
*
* @returns the size of the slot that @p state is configured to update to
*/
size_t riotboot_flashwrite_slotsize(const riotboot_flashwrite_t *state);
/**
* @brief Verify the digest of an image
*
* @param[in] sha256_digest content of the image digest
* @param[in] img_size the size of the image
* @param[in] target_slot the image slot number
*
* @returns -1 when image is too small
* @returns 0 if the digest is valid
* @returns 1 if the digest is invalid
*/
int riotboot_flashwrite_verify_sha256(const uint8_t *sha256_digest,
size_t img_size, int target_slot);
#ifdef __cplusplus
}
#endif
#endif /* RIOTBOOT_FLASHWRITE_H */