ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_ota.c
Go to the documentation of this file.
1
30
31#include "ra8_ota.h"
32
33#include <stddef.h>
34#include <stdint.h>
35#include <string.h>
36
37#include "ra8_attributes.h"
38#include "ra8_check.h"
39#include "ra8_err.h"
40#include "ra8_ota_internal.h"
41#include "ra8_secure.h"
42
43/* =============================================================================
44 * Module-static storage
45 * ============================================================================= */
46
48static const char* const s_tag = "ra8_ota";
49
52
55
58
61
63static bool s_manifest_valid = false;
64
66static uint32_t s_bytes_done = 0U;
67
70
73
74/* =============================================================================
75 * Internal helpers
76 * ============================================================================= */
77
81{
82 g_ra8_ota_state = new_state;
83 s_last_err = err;
84 if (g_ra8_ota_cfg.on_progress != nullptr) {
85 const ra8_ota_progress_t snap = {
86 .state = new_state,
87 .bytes_done = s_bytes_done,
88 .bytes_total = s_manifest_valid ? s_manifest.image_size_bytes : 0U,
89 .last_err = err,
90 };
91 g_ra8_ota_cfg.on_progress(&snap);
92 }
93}
94
121static ra8_err_t internal_drain(uint8_t* dst, uint32_t cap, uint32_t* out_n)
122{
123 uint32_t total = 0U;
124 /* Bounded loop: each iteration must consume >= 1 byte or hit EOF. */
125 for (uint32_t guard = 0U; guard < cap + 1U; ++guard) {
126 if (total >= cap) {
127 break;
128 }
129 uint32_t got = 0U;
130 const ra8_err_t e =
131 g_ra8_ota_cfg.net.read(g_ra8_ota_cfg.net.ctx, dst + total, cap - total, &got);
132 if (e != k_ra8_ok) {
133 return e;
134 }
135 if (got == 0U) {
136 break; /* EOF */
137 }
138 total += got;
139 }
140 *out_n = total;
141 return k_ra8_ok;
142}
143
144/* =============================================================================
145 * Public API
146 * ============================================================================= */
147
183{
186 }
187 const ra8_err_t e = priv_ota_validate_cfg(cfg);
188 if (e != k_ra8_ok) {
189 return e;
190 }
191 (void)memcpy(&g_ra8_ota_cfg, cfg, sizeof g_ra8_ota_cfg);
193 s_manifest_valid = false;
194 s_bytes_done = 0U;
197 /* run_as_thread is honoured by an external adapter -- on host the
198 * caller drives ra8_ota_run_step() directly. */
199 return k_ra8_ok;
200}
201
225{
226 g_ra8_ota_initialized = false;
228 s_manifest_valid = false;
229 s_bytes_done = 0U;
231 (void)memset(&g_ra8_ota_cfg, 0, sizeof g_ra8_ota_cfg);
232 return k_ra8_ok;
233}
234
261
288{
289 uint32_t content_len = 0U;
290 ra8_err_t e =
291 g_ra8_ota_cfg.net.open(g_ra8_ota_cfg.net.ctx, g_ra8_ota_cfg.manifest_url, &content_len);
292 if (e != k_ra8_ok) {
293 return e;
294 }
295 if (content_len > k_ra8_ota_manifest_max_bytes) {
296 (void)g_ra8_ota_cfg.net.close(g_ra8_ota_cfg.net.ctx);
298 }
299 uint32_t got = 0U;
301 (void)g_ra8_ota_cfg.net.close(g_ra8_ota_cfg.net.ctx);
302 if (e != k_ra8_ok) {
303 return e;
304 }
305 g_ra8_ota_buf[got] = 0U; /* NUL terminate so JSON helpers can use strstr. */
306 *out_got = got;
307 return k_ra8_ok;
308}
309
339{
342 }
343 RA8_CHECK_NULL_PTR(out_manifest, s_tag, "out_manifest");
346 }
348
349 uint32_t got = 0U;
351 if (e != k_ra8_ok) {
353 return e;
354 }
355
356 e = priv_ota_manifest_decode((const char*)g_ra8_ota_buf, out_manifest);
357 if (e != k_ra8_ok) {
359 return e;
360 }
361 (void)memcpy(&s_manifest, out_manifest, sizeof s_manifest);
362 s_manifest_valid = true;
364 return k_ra8_ok;
365}
366
394static ra8_err_t internal_download_chunk(uint32_t addr_base, uint32_t* in_out_done, uint32_t total)
395{
396 const uint32_t remaining = total - *in_out_done;
397 const uint32_t want = (remaining < k_ra8_ota_chunk_bytes) ? remaining : k_ra8_ota_chunk_bytes;
398 uint32_t got = 0U;
399 ra8_err_t e = internal_drain(g_ra8_ota_buf, want, &got);
400 if (e != k_ra8_ok) {
401 return e;
402 }
403 if (got == 0U) {
404 return k_ra8_err_hw_error;
405 }
406 e = g_ra8_ota_cfg.crypto.sha256_update(g_ra8_ota_cfg.crypto.ctx, g_ra8_ota_buf, got);
407 if (e != k_ra8_ok) {
408 return e;
409 }
410 e = g_ra8_ota_cfg.flash.program(g_ra8_ota_cfg.flash.ctx,
411 addr_base + *in_out_done,
413 got);
414 if (e != k_ra8_ok) {
415 return e;
416 }
417 *in_out_done += got;
419 return k_ra8_ok;
420}
421
447{
448 ra8_err_t e = g_ra8_ota_cfg.flash.erase(g_ra8_ota_cfg.flash.ctx,
449 g_ra8_ota_cfg.flash.inactive_bank_addr,
450 manifest->image_size_bytes);
451 if (e != k_ra8_ok) {
452 return e;
453 }
454 return g_ra8_ota_cfg.crypto.sha256_init(g_ra8_ota_cfg.crypto.ctx);
455}
456
483{
484 const uint32_t max_chunks = (k_ra8_ota_max_image_bytes / k_ra8_ota_chunk_bytes) + 1U;
485 uint32_t chunks = 0U;
487 while (s_bytes_done < manifest->image_size_bytes) {
488 /* Validation ensures image_size <= k_ra8_ota_max_image_bytes == 128 *
489 * k_ra8_ota_chunk_bytes, so chunk count never exceeds 128 < max_chunks. */
490 if (chunks >= max_chunks) {
491 e = k_ra8_err_hw_error; /* GCOVR_EXCL_LINE -- chunk-budget exhaustion never reached */
492 break; /* GCOVR_EXCL_LINE -- chunk-budget exhaustion never reached */
493 }
494 e = internal_download_chunk(g_ra8_ota_cfg.flash.inactive_bank_addr,
496 manifest->image_size_bytes);
497 if (e != k_ra8_ok) {
498 break;
499 }
500 ++chunks;
501 }
502 return e;
503}
504
535{
538 }
539 RA8_CHECK_NULL_PTR(manifest, s_tag, "manifest");
542 (uint32_t)g_ra8_ota_state)) {
544 }
545 if (manifest->image_size_bytes > g_ra8_ota_cfg.flash.bank_size_bytes) {
548 }
549
550 if (s_bytes_done == 0U) {
551 const ra8_err_t e = internal_prepare_bank(manifest);
552 if (e != k_ra8_ok) {
554 return e;
555 }
556 }
557
558 uint32_t content_len = 0U;
559 ra8_err_t e = g_ra8_ota_cfg.net.open(g_ra8_ota_cfg.net.ctx, manifest->image_url, &content_len);
560 if (e != k_ra8_ok) {
562 return e;
563 }
565
566 e = internal_download_loop(manifest);
567 (void)g_ra8_ota_cfg.net.close(g_ra8_ota_cfg.net.ctx);
568
569 if (e != k_ra8_ok) {
571 return e;
572 }
574 return k_ra8_ok;
575}
576
604{
607 }
610 }
611 const ra8_err_t e = g_ra8_ota_cfg.flash.set_startup(g_ra8_ota_cfg.flash.ctx,
612 g_ra8_ota_cfg.flash.inactive_bank_index,
613 true);
614 if (e != k_ra8_ok) {
616 return e;
617 }
619 /* On hardware ra8_ota_system_reset_hook is overridden to call
620 * NVIC_SystemReset; in the host build it is a no-op. */
622 return k_ra8_ok;
623}
624
650{
651 switch (g_ra8_ota_state) {
653 /* If a previous run_step already fetched and validated the
654 * manifest, advance to download instead of re-fetching it. */
655 if (s_manifest_valid) {
657 }
659 return ra8_ota_check_for_update(&m);
660 }
661 /* checking and downloading are always resolved synchronously within a
662 * single API call; internal_step_dispatch is never entered while the SM
663 * holds one of these transient states in the host build. */
666 if (s_manifest_valid) {
668 }
677 default:
678 return k_ra8_ok;
679 }
680}
681
708{
711 }
712 return internal_step_dispatch();
713}
714
741{
744 }
745 /* Bounded by the longest legal sequence (idle -> checking ->
746 * downloading -> verifying -> committing -> done). Six steps is
747 * the upper bound; pad to ``k_ra8_ota_state_count`` for safety. */
748 for (uint32_t i = 0U; i < (uint32_t)k_ra8_ota_state_count; ++i) {
750 break;
751 }
752 const ra8_err_t e = ra8_ota_run_step();
753 if (e != k_ra8_ok) {
754 return e;
755 }
756 }
757 return s_last_err;
758}
759
760/* =============================================================================
761 * Weak system-reset hook: real target overrides this with
762 * ``NVIC_SystemReset()``. Default is a no-op so unit tests don't
763 * actually exit the process.
764 * ============================================================================= */
765
788#if defined(__GNUC__) || defined(__clang__)
789[[gnu::weak]]
790#endif
792{
793 /* Intentionally empty. */
794}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_PRIV
Module-private helper: shared across TUs but only inside one library.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
void * memcpy(void *dst, const void *src, size_t n)
Copy memory area between non-overlapping regions.
ra8_err_t ra8_ota_run_step(void)
Drive the OTA state machine one step forward.
Definition ra8_ota.c:707
ra8_err_t ra8_ota_commit_and_reboot(void)
Latch the inactive bank as the next boot bank and reboot.
Definition ra8_ota.c:603
void ra8_ota_system_reset_hook(void)
Weak system-reset hook overridden by the target build.
Definition ra8_ota.c:791
static ra8_err_t internal_prepare_bank(const ra8_ota_manifest_t *manifest)
Erase the inactive bank and prime the SHA accumulator.
Definition ra8_ota.c:446
static ra8_err_t internal_drain(uint8_t *dst, uint32_t cap, uint32_t *out_n)
Drain the network stream and accumulate up to cap bytes.
Definition ra8_ota.c:121
static ra8_err_t internal_step_dispatch(void)
Drive one transition based on the current state.
Definition ra8_ota.c:649
static ra8_err_t internal_fetch_manifest_payload(uint32_t *out_got)
Open the manifest URL and drain its payload into g_ra8_ota_buf.
Definition ra8_ota.c:287
static ra8_err_t internal_download_chunk(uint32_t addr_base, uint32_t *in_out_done, uint32_t total)
Stream one chunk: drain network -> hash -> flash program.
Definition ra8_ota.c:394
bool g_ra8_ota_initialized
True once ra8_ota_init succeeded (shared; contract in ra8_ota_internal.h).
Definition ra8_ota.c:57
static bool s_manifest_valid
Whether s_manifest holds a valid payload.
Definition ra8_ota.c:63
static ra8_ota_manifest_t s_manifest
Cached decoded manifest from the most recent check.
Definition ra8_ota.c:60
ra8_err_t ra8_ota_download_to_inactive_bank(const ra8_ota_manifest_t *manifest)
Download an image into the inactive bank, hashing as it goes.
Definition ra8_ota.c:534
ra8_ota_state_t g_ra8_ota_state
Current state-machine value (shared; contract in ra8_ota_internal.h).
Definition ra8_ota.c:51
static ra8_err_t s_last_err
Last error observed by the state machine.
Definition ra8_ota.c:69
uint8_t g_ra8_ota_buf[k_ra8_ota_chunk_bytes]
Streaming buffer (shared; contract in ra8_ota_internal.h).
Definition ra8_ota.c:72
ra8_err_t ra8_ota_run_full_update(void)
Drive the OTA state machine through an end-to-end update.
Definition ra8_ota.c:740
void priv_ota_set_state(ra8_ota_state_t new_state, ra8_err_t err)
Implementation of priv_ota_set_state() – latch state + progress fan-out.
Definition ra8_ota.c:80
ra8_err_t ra8_ota_init(const ra8_ota_cfg_t *cfg)
Initialise the OTA module from a caller-supplied configuration.
Definition ra8_ota.c:182
ra8_ota_state_t ra8_ota_get_state(void)
Return the current OTA state-machine value.
Definition ra8_ota.c:257
ra8_err_t ra8_ota_check_for_update(ra8_ota_manifest_t *out_manifest)
Fetch and decode the upstream manifest, leaving it cached.
Definition ra8_ota.c:338
ra8_ota_cfg_t g_ra8_ota_cfg
Configuration captured at init time (shared; contract in ra8_ota_internal.h).
Definition ra8_ota.c:54
static ra8_err_t internal_download_loop(const ra8_ota_manifest_t *manifest)
Drain chunks until the entire image is downloaded or an error fires.
Definition ra8_ota.c:482
static uint32_t s_bytes_done
Bytes already programmed into the inactive bank.
Definition ra8_ota.c:66
ra8_err_t ra8_ota_deinit(void)
Reset the OTA module to its un-initialized state.
Definition ra8_ota.c:224
Phase-5 OTA firmware-update orchestration for the RA8D2.
ra8_ota_state_t
Cooperative state-machine states.
Definition ra8_ota.h:91
@ k_ra8_ota_state_count
Sentinel.
Definition ra8_ota.h:99
@ k_ra8_ota_state_error
Last operation failed; see last err.
Definition ra8_ota.h:98
@ k_ra8_ota_state_checking
Manifest fetch in flight.
Definition ra8_ota.h:93
@ k_ra8_ota_state_verifying
SHA-256 + ECDSA verification.
Definition ra8_ota.h:95
@ k_ra8_ota_state_done
Update applied (reset is imminent).
Definition ra8_ota.h:97
@ k_ra8_ota_state_committing
About to swap banks + reset.
Definition ra8_ota.h:96
@ k_ra8_ota_state_downloading
Streaming firmware to inactive bank.
Definition ra8_ota.h:94
@ k_ra8_ota_state_idle
No update in progress.
Definition ra8_ota.h:92
ra8_err_t ra8_ota_verify_signature(const ra8_ota_manifest_t *manifest)
Verify SHA-256 + ECDSA over the freshly programmed bank.
@ k_ra8_ota_chunk_bytes
Download streaming chunk size in bytes.
Definition ra8_ota.h:73
@ k_ra8_ota_max_image_bytes
512 KiB upper bound per bank.
Definition ra8_ota.h:79
@ k_ra8_ota_manifest_max_bytes
Largest accepted manifest payload.
Definition ra8_ota.h:74
Test-access surface for ra8_ota internal helpers (MC/DC).
ra8_err_t priv_ota_manifest_decode(const char *json, ra8_ota_manifest_t *out)
Decode every field of a JSON manifest into an ra8_ota_manifest_t.
ra8_err_t priv_ota_validate_cfg(const ra8_ota_cfg_t *cfg)
Validate the entire OTA configuration descriptor.
bool priv_ota_download_state_invalid(uint32_t state_idle_val, uint32_t state_downloading_val, uint32_t state)
Pure predicate: state is neither IDLE nor DOWNLOADING.
Secure-comparison primitives for the crypto / secure-boot paths.
Initialisation descriptor for ra8_ota_init.
Definition ra8_ota.h:258
Decoded representation of the server manifest.
Definition ra8_ota.h:115
char image_url[k_ra8_ota_url_max_bytes]
HTTPS URL of the image blob.
Definition ra8_ota.h:117
uint32_t image_size_bytes
Image size on the wire.
Definition ra8_ota.h:118
Snapshot delivered to the caller's progress callback.
Definition ra8_ota.h:128