25#include <mbedtls/sha256.h>
28#include <zephyr/dfu/flash_img.h>
29#include <zephyr/dfu/mcuboot.h>
30#include <zephyr/retention/blinfo.h>
31#include <zephyr/retention/retention.h>
32#include <zephyr/storage/flash_map.h>
33#include <zephyr/storage/stream_flash.h>
38static const struct device *otamem_dev =
39 DEVICE_DT_GET(DT_NODELABEL(ota_retention));
41static etl::string<CONFIG_STORAGE_MAX_PATH_LEN> littlefs_path;
43static mbedtls_sha256_context sha256_ctx;
44static uint8_t ota_buffer[CONFIG_OTA_BUFFER_SIZE];
45static etl::string<64> log_str;
46static struct flash_img_context flash_ctx_littlefs;
47static struct flash_img_context flash_ctx_slot0;
48static struct flash_img_context flash_ctx_slot1;
50static uint8_t slots_to_area[2] = {FIXED_PARTITION_ID(slot0_partition),
51 FIXED_PARTITION_ID(slot1_partition)};
57 if (
id > CONFIG_OTA_MAX_SESSIONS - 1) {
68 for (uint32_t i = 0; i < CONFIG_OTA_MAX_SESSIONS; i++) {
77 if (
id > CONFIG_OTA_MAX_SESSIONS - 1)
91 for (uint32_t i = 0; i < CONFIG_OTA_MAX_SESSIONS; i++) {
92 if (m_sessions[i].active ==
false || m_sessions[i].applied) {
126 if (!boot_is_img_confirmed()) {
139 uint8_t active_slot = boot_fetch_active_slot();
142 etl::string_stream stream(log_str);
143 stream <<
"Active slot (" << active_slot <<
") cannot be updated";
149 int ret = flash_img_init_id(
154 etl::string_stream stream(log_str);
155 stream <<
"flash_img_init_id() error " << ret;
171 littlefs_path.clear();
181 littlefs_path.clear();
182 etl::string_stream stream(littlefs_path);
194 log.log(
"Invalid OTA subsystem");
201 m_sessions[idx].
active =
true;
202 std::copy_n(req.
sha256, 32, m_sessions[idx].sha256);
203 m_sessions[idx].total_size = req.
size;
204 m_sessions[idx].name = req.
name;
205 m_sessions[idx].destination = req.
dst;
206 m_sessions[idx].slot = req.
slot;
210 update_retention(idx);
220 if (tlc.
session > CONFIG_OTA_MAX_SESSIONS - 1) {
225 auto &ctx = m_sessions[tlc.
session];
226 if (ctx.active ==
false) {
232 if (tlc.
seq != ctx.ack) {
238 switch (ctx.destination) {
242 if (!boot_is_img_confirmed()) {
254 switch (ctx.destination) {
257 res = write_slot(ctx, tlc);
260 res = write_wic(ctx, tlc);
263 res = write_littlefs(
true, ctx, tlc);
266 res = write_littlefs(
false, ctx, tlc);
287 if (tlc.
session > CONFIG_OTA_MAX_SESSIONS - 1) {
292 auto &ctx = m_sessions[tlc.
session];
293 if (ctx.active ==
false) {
299 if (ctx.ack != ctx.total_size) {
304 if (sha256_check(ctx, wdgid) ==
false) {
312 switch (ctx.destination) {
315 if (!boot_is_img_confirmed()) {
320 finalize_mcu(ctx, tlm);
323 if (!boot_is_img_confirmed()) {
328 finalize_littlefs_to_mcu(ctx, tlm);
348 boot_write_img_confirmed();
353 static_assert(
sizeof(
session) * CONFIG_OTA_MAX_SESSIONS <
355 k_mutex_init(&m_mtx);
357 if (retention_is_valid(otamem_dev)) {
364 retention_read(otamem_dev, 0,
reinterpret_cast<uint8_t *
>(&n),
367 retention_read(otamem_dev,
sizeof(uint32_t),
368 reinterpret_cast<uint8_t *
>(&hash),
sizeof(uint32_t));
373 for (uint32_t i = 0; i < CONFIG_OTA_MAX_SESSIONS; i++) {
375 retention_read(otamem_dev, 2 *
sizeof(uint32_t) + i *
sizeof(s),
376 reinterpret_cast<uint8_t *
>(&s),
sizeof(s));
404ota::reset_retention()
406 retention_clear(otamem_dev);
408 uint32_t x = CONFIG_OTA_MAX_SESSIONS;
409 retention_write(otamem_dev, 0,
reinterpret_cast<const uint8_t *
>(&x),
413 retention_write(otamem_dev,
sizeof(uint32_t),
414 reinterpret_cast<const uint8_t *
>(&x),
sizeof(uint32_t));
417 for (uint32_t i = 0; i < CONFIG_OTA_MAX_SESSIONS; i++) {
419 retention_write(otamem_dev, 2 *
sizeof(uint32_t) + i *
sizeof(s),
420 reinterpret_cast<const uint8_t *
>(&s),
sizeof(s));
425ota::update_retention(uint32_t idx)
427 retention_write(otamem_dev, 2 *
sizeof(uint32_t) + idx *
sizeof(
session),
428 reinterpret_cast<const uint8_t *
>(&m_sessions[idx]),
433ota::write_slot(session &s,
const data_tlc &tlc)
437 uint8_t active_slot = boot_fetch_active_slot();
441 etl::string_stream stream(log_str);
442 stream <<
"Cannot write to active slot " << active_slot;
447 switch (s.destination) {
449 flash_img_buffered_write(&flash_ctx_slot0, tlc.data, tlc.len,
false);
452 flash_img_buffered_write(&flash_ctx_slot1, tlc.data, tlc.len,
false);
456 log.log(
"Invalid destination. Only MCU_SLOT0 and MCU_SLOT1 are "
465ota::write_wic(session &s,
const data_tlc &tlc)
467 uint32_t ncopy = tlc.len;
468 if (s.ack + tlc.len > s.total_size) {
469 ncopy = s.ack + tlc.len - s.total_size;
481ota::write_littlefs(
bool mcu, session &s,
const data_tlc &tlc)
483 uint32_t ncopy = tlc.len;
484 if (s.ack + tlc.len > s.total_size) {
485 ncopy = s.ack + tlc.len - s.total_size;
488 littlefs_path.clear();
489 etl::string_stream stream(littlefs_path);
493 int ret = storage.write(littlefs_path, tlc.data, ncopy);
498 uint32_t written =
static_cast<uint32_t
>(ret);
512ota::sha256_check(
const session &s,
int wdgid)
514 switch (s.destination) {
517 return sha256_mcu(s);
519 return sha256_fpga_wic(s, wdgid);
522 littlefs_path.clear();
523 etl::string_stream stream(littlefs_path);
527 return sha256_littlefs(s, littlefs_path, wdgid);
535ota::sha256_littlefs(
const session &s,
const etl::istring &path,
int wdgid)
537 auto ts = k_uptime_seconds();
538 mbedtls_sha256_init(&sha256_ctx);
539 mbedtls_sha256_starts(&sha256_ctx, 0);
541 const uint32_t iters = s.total_size / CONFIG_OTA_BUFFER_SIZE;
542 storage::file f(path);
543 for (uint32_t i = 0; i < iters; i++) {
548 auto now = k_uptime_seconds();
550 task_wdt_feed(wdgid);
554 storage.read(f, ota_buffer, CONFIG_OTA_BUFFER_SIZE);
555 mbedtls_sha256_update(&sha256_ctx, ota_buffer, CONFIG_OTA_BUFFER_SIZE);
558 if (s.total_size % CONFIG_OTA_BUFFER_SIZE) {
559 storage.read(f, ota_buffer, s.total_size % CONFIG_OTA_BUFFER_SIZE);
560 mbedtls_sha256_update(&sha256_ctx, ota_buffer,
561 s.total_size % CONFIG_OTA_BUFFER_SIZE);
563 mbedtls_sha256_finish(&sha256_ctx, ota_buffer);
564 mbedtls_sha256_free(&sha256_ctx);
565 return std::equal(s.sha256, s.sha256 + 32, ota_buffer);
569ota::sha256_fpga_wic(
const session &s,
int wdgid)
571 auto ts = k_uptime_seconds();
572 mbedtls_sha256_init(&sha256_ctx);
573 mbedtls_sha256_starts(&sha256_ctx, 0);
576 for (uint32_t i = 0; i < nsectors; i++) {
581 auto now = k_uptime_seconds();
583 task_wdt_feed(wdgid);
587 storage.read_raw(ota_buffer, i, 1);
592 storage.read_raw(ota_buffer, nsectors, 1);
593 mbedtls_sha256_update(&sha256_ctx, ota_buffer,
596 mbedtls_sha256_finish(&sha256_ctx, ota_buffer);
597 mbedtls_sha256_free(&sha256_ctx);
598 return std::equal(s.sha256, s.sha256 + 32, ota_buffer);
602ota::sha256_mcu(
const session &s)
604 struct flash_img_check check;
605 check.clen = s.total_size;
606 check.match = s.sha256;
614 flash_img_buffered_write(&flash_ctx_slot0, ota_buffer, 0,
true);
615 ret = flash_img_check(&flash_ctx_slot0, &check, slots_to_area[0]);
617 flash_img_buffered_write(&flash_ctx_slot1, ota_buffer, 0,
true);
618 ret = flash_img_check(&flash_ctx_slot1, &check, slots_to_area[1]);
624ota::finalize_littlefs_to_mcu(session &s, response_tlm &tlm)
629 etl::string_stream stream(log_str);
630 stream <<
"Invalid slot number " << s.slot;
640 uint8_t curr_slot = boot_fetch_active_slot();
641 if (curr_slot == slots_to_area[s.slot]) {
643 etl::string_stream stream(log_str);
644 stream <<
"Active slot and update slot is the same (" << s.slot <<
")";
650 int ret = flash_img_init_id(&flash_ctx_littlefs, slots_to_area[s.slot]);
653 etl::string_stream stream(log_str);
654 stream <<
"flash_img_init_id() error " << ret;
660 littlefs_path.clear();
661 etl::string_stream stream(littlefs_path);
663 storage::file f(littlefs_path);
664 const uint32_t iters = s.total_size / CONFIG_IMG_BLOCK_BUF_SIZE;
666 for (uint32_t i = 0; i < iters; i++) {
667 storage.read(f, ota_buffer, CONFIG_IMG_BLOCK_BUF_SIZE);
668 flash_img_buffered_write(&flash_ctx_littlefs, ota_buffer,
669 CONFIG_IMG_BLOCK_BUF_SIZE,
false);
671 storage.read(f, ota_buffer, s.total_size % CONFIG_IMG_BLOCK_BUF_SIZE);
672 flash_img_buffered_write(&flash_ctx_littlefs, ota_buffer,
673 s.total_size % CONFIG_IMG_BLOCK_BUF_SIZE,
true);
675 boot_request_upgrade(BOOT_UPGRADE_TEST);
677 sys_reboot(SYS_REBOOT_COLD);
683ota::finalize_mcu(session &s, response_tlm &tlm)
686 int ret = boot_request_upgrade(BOOT_UPGRADE_TEST);
690 sys_reboot(SYS_REBOOT_COLD);
static logger & get_instance()
Singleton access to the logger subsystem.
etl::string< MAX_FILE_LEN > name
static constexpr size_t HASH
etl::string< MAX_FILE_LEN > name
@ CURRENT_IMG_NOT_CONFIRMED
void recv(const data_tlc &tlc, response_tlm &tlm)
static constexpr const char * LITTLEFS_FPGA_DIR
void finalize(const fin_tlc &tlc, response_tlm &tlm, int wdgid)
void reset_session(uint32_t id)
static constexpr const char * LITTLEFS_MCU_DIR
static constexpr size_t OTA_RETENTION_MEM_SIZE
The available retention memory for the OTA service.
@ MCU_SLOT1
MCU MCUBoot Slot 1.
@ MCU_SLOT0
MCU MCUBoot Slot 0.
void start(const start_tlc &req, response_tlm &tlm)
void confirm_image()
Sets the running firmware as confirmed.
bool get_session_info(uint8_t id, session &out) const
Implements a scoped lock utilizing the Zephyr mutex.
void mkdir(const etl::istring &path)
Creates a directory at the specified path.
static storage & get_instance()
void rm(const etl::istring &path)
Removes a file from the filesystem.
static constexpr size_t SECTOR_SIZE