/* * Copyright (C) 2019 Inria * 2019 Freie Universität Berlin * 2019 Kaspar Schleiser * * 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_riotboot_flashwrite * @{ * * @file * @brief Firmware update helper functions * * @author Kaspar Schleiser * * @} */ #include #include #include "riotboot/flashwrite.h" #include "od.h" #define LOG_PREFIX "riotboot_flashwrite: " #include "log.h" static inline size_t min(size_t a, size_t b) { return a <= b ? a : b; } size_t riotboot_flashwrite_slotsize(const riotboot_flashwrite_t *state) { switch (state->target_slot) { case 0: return SLOT0_LEN; #if NUM_SLOTS==2 case 1: return SLOT1_LEN; #endif default: return 0; } } int riotboot_flashwrite_init_raw(riotboot_flashwrite_t *state, int target_slot, size_t offset) { assert(offset <= FLASHPAGE_SIZE); LOG_INFO(LOG_PREFIX "initializing update to target slot %i\n", target_slot); memset(state, 0, sizeof(riotboot_flashwrite_t)); state->offset = offset; state->target_slot = target_slot; state->flashpage = flashpage_page((void *)riotboot_slot_get_hdr(target_slot)); return 0; } int riotboot_flashwrite_putbytes(riotboot_flashwrite_t *state, const uint8_t *bytes, size_t len, bool more) { LOG_DEBUG(LOG_PREFIX "processing bytes %u-%u\n", state->offset, state->offset + len - 1); while (len) { size_t flashpage_pos = state->offset % FLASHPAGE_SIZE; size_t flashpage_avail = FLASHPAGE_SIZE - flashpage_pos; size_t to_copy = min(flashpage_avail, len); memcpy(state->flashpage_buf + flashpage_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) { LOG_WARNING(LOG_PREFIX "error writing flashpage %u!\n", state->flashpage); return -1; } state->flashpage++; } } return 0; } int riotboot_flashwrite_finish_raw(riotboot_flashwrite_t *state, const uint8_t *bytes, size_t len) { assert(len <= FLASHPAGE_SIZE); int res = -1; uint8_t *slot_start = (uint8_t *)riotboot_slot_get_hdr(state->target_slot); uint8_t *firstpage; if (len < FLASHPAGE_SIZE) { firstpage = state->flashpage_buf; memcpy(firstpage, bytes, len); memcpy(firstpage + len, slot_start + len, FLASHPAGE_SIZE - len); } else { firstpage = (void *)bytes; } int flashpage = flashpage_page((void *)slot_start); if (flashpage_write_and_verify(flashpage, firstpage) != FLASHPAGE_OK) { LOG_WARNING(LOG_PREFIX "re-flashing first block failed!\n"); goto out; } LOG_INFO(LOG_PREFIX "riotboot flashing completed successfully\n"); res = 0; out: return res; }