ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_dfu.h File Reference

Controller-agnostic USB-DFU MRAM bootloader core for the RA8D2. More...

#include <stdint.h>
#include "ra8_err.h"
Include dependency graph for ra8_dfu.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ra8_dfu_img_hdr_t
 32-byte application-image header at the base of each slot. More...

Enumerations

enum  ra8_dfu_layout_t : uint32_t {
  k_ra8_dfu_mram_base = 0x02000000U ,
  k_ra8_dfu_mram_size = 0x00100000U ,
  k_ra8_dfu_bl_size = 0x00020000U ,
  k_ra8_dfu_slot_a_base = 0x02020000U ,
  k_ra8_dfu_slot_b_base = 0x02090000U ,
  k_ra8_dfu_slot_size = 0x00070000U ,
  k_ra8_dfu_page_size = 0x00000020U ,
  k_ra8_dfu_hdr_size = 0x00000020U ,
  k_ra8_dfu_img_max = 0x0006FFE0U ,
  k_ra8_dfu_hdr_offset = 0x0006FFE0U ,
  k_ra8_dfu_hdr_magic = 0x52413844U ,
  k_ra8_dfu_trigger_magic = 0xDF00B007U
}
 Fixed MRAM bank-layout addresses and image-header constants. More...
enum  ra8_dfu_run_t : uint32_t { k_ra8_dfu_run_base = 0x22020000U }
 Fixed SRAM copy-to-run execution base. More...
enum  ra8_dfu_slot_t : uint8_t {
  k_ra8_dfu_slot_a = 0U ,
  k_ra8_dfu_slot_b = 1U ,
  k_ra8_dfu_slot_none = 2U
}
 Application-slot identifier. More...
enum  ra8_dfu_action_t : uint8_t {
  k_ra8_dfu_action_dfu = 0U ,
  k_ra8_dfu_action_jump_a = 1U ,
  k_ra8_dfu_action_jump_b = 2U
}
 Outcome of the reset-time boot decision. More...

Functions

uint32_t ra8_dfu_crc32 (const uint8_t *data, uint32_t len)
 Compute the IEEE-802.3 CRC32 of a byte range (software).
bool ra8_dfu_hdr_valid (const ra8_dfu_img_hdr_t *hdr, uint32_t computed_crc)
 Decide whether a slot header describes a valid bootable image.
bool ra8_dfu_run_target_valid (uint32_t entry, uint32_t img_len)
 Decide whether a validated slot's image may be copied-to-run.
void ra8_dfu_launch (uintptr_t src, uint32_t img_len, uint32_t entry)
 Copy an image to the SRAM run base and branch to it (copy-to-run).
ra8_dfu_slot_t ra8_dfu_select_slot (bool a_valid, uint32_t a_seq, bool b_valid, uint32_t b_seq)
 Pick the active slot from the two slots' validity + sequence.
ra8_dfu_action_t ra8_dfu_boot_decide (bool dfu_trigger, bool a_valid, uint32_t a_seq, bool b_valid, uint32_t b_seq)
 Reset-time boot decision: jump to a slot, or enter DFU.
uintptr_t ra8_dfu_slot_base (ra8_dfu_slot_t slot)
 Return the MRAM base address of a slot.
ra8_dfu_slot_t ra8_dfu_other_slot (ra8_dfu_slot_t slot)
 Return the opposite slot (A<->B).
ra8_err_t ra8_dfu_read_header (ra8_dfu_slot_t slot, ra8_dfu_img_hdr_t *out_hdr)
 Copy a slot's 32-byte header out of MRAM.
bool ra8_dfu_slot_valid (ra8_dfu_slot_t slot)
 Validate a slot live: header magic/length/CRC over its real image.
ra8_err_t ra8_dfu_slot_seq (ra8_dfu_slot_t slot, uint32_t *out_seq)
 Read a slot header's sequence number (0 if the magic is wrong).
ra8_err_t ra8_dfu_program_prepare (ra8_dfu_slot_t inactive)
 Open ra8_flash and fence all writes to one slot's window.
ra8_err_t ra8_dfu_program_image (ra8_dfu_slot_t inactive, uint32_t img_offset, const uint8_t *data, uint32_t len)
 Program one image chunk into the inactive slot's body.
ra8_err_t ra8_dfu_program_commit (ra8_dfu_slot_t inactive, uint32_t img_len, uint32_t seq)
 Finalize a slot: CRC the programmed body, then program the header.
ra8_err_t ra8_dfu_program_verify (ra8_dfu_slot_t slot)
 Read-back verify: re-CRC a slot's body against its stored header.

Detailed Description

Controller-agnostic USB-DFU MRAM bootloader core for the RA8D2.

Tag
[Ring 4 / Service] {World: S}

Shared core behind the real dfu_bootloader app and the two bidirectional HIL self-loop twins (dfu_selftest_hs_host / dfu_selftest_fs_host). It bundles three concerns:

  • Pure boot logic (this header + ra8_dfu_boot.c): image-header validation, A/B slot selection, the boot-vs-DFU decision, and a software CRC32. No MMIO, no USB – trivially host-unit-testable.
  • MRAM program/verify (ra8_dfu_program.c): stage + erase + program + read-back-verify of the inactive slot over ra8_flash, with the write path placed in SRAM (the code-MRAM program loop must not execute from MRAM – see ra8_flash.h).
  • DFU device + host glue (ra8_dfu_device.c / ra8_dfu_host.c): USBX DFU class callbacks wired to real MRAM, and the polled host DFU driver – both bound to EITHER controller through the ux_dcd_ra8_usb bridge via a ra8_usb_speed_t parameter.

Bank layout (1 MiB MRAM, fixed bootloader + software A/B slots)

0x02000000 bootloader 128 KiB (immutable; never erased by DFU)
0x02020000 Slot A 448 KiB [app image | 32B header (last page)]
0x02090000 Slot B 448 KiB [app image | 32B header (last page)]
0x02100000 (end)

The bootloader is 128 KiB so a full USBX + ThreadX DFU device fits inside the immutable region; the two app slots fill the rest of the 1 MiB array.

Copy-to-run (one image, either slot)

A slot is staging only: the image body occupies [slot_base, slot_base + img_len) and the 32-byte header is the slot's LAST page (slot_base + k_ra8_dfu_hdr_offset), programmed last so a torn download leaves an invalid (CRC-mismatching) slot rather than a half-valid one. On a valid-slot boot the bootloader COPIES the body to a single fixed SRAM run base (k_ra8_dfu_run_base) and launches it there. A payload is therefore linked ONCE, at the run base, and the identical image boots from either slot – no per-slot build and no "which slot am I building for?" footgun. This sidesteps true position-independent code (ROPI/RWPI), which cannot relocate the absolute function pointers this codebase's interface structs store in .rodata.

The header's entry records that run base. The bootloader copies to the trusted k_ra8_dfu_run_base constant (not to entry), so a corrupted entry cannot redirect the copy – it only fails the ra8_dfu_run_target_valid cross-check, which drops the boot to DFU. (Header-last is kept purely for the torn-write atomicity above; the old VTOR-alignment reason no longer applies, since VTOR is set to the aligned run base, not the slot.)

The bootloader is never swapped (no BTFLG / startup-area swap); it reads both slot headers and jumps to the valid slot with the higher sequence number in software. A freshly-written bad slot fails its CRC, so the older valid slot is chosen automatically – brick-safe by construction, and SWD recovery is always available because the bootloader region is never written.

Definition in file ra8_dfu.h.

Enumeration Type Documentation

◆ ra8_dfu_action_t

enum ra8_dfu_action_t : uint8_t

Outcome of the reset-time boot decision.

Enumerator
k_ra8_dfu_action_dfu 

Enter the DFU device; do not jump.

k_ra8_dfu_action_jump_a 

Jump to the Slot A application.

k_ra8_dfu_action_jump_b 

Jump to the Slot B application.

Definition at line 143 of file ra8_dfu.h.

◆ ra8_dfu_layout_t

enum ra8_dfu_layout_t : uint32_t

Fixed MRAM bank-layout addresses and image-header constants.

The 1 MiB code-MRAM window splits into a 64 KiB immutable bootloader plus two equal 480 KiB application slots. Every numeric address / size / magic the core needs is named here (CLAUDE.md "C23 typed enums"; NASA Rule 8). HUM Ch 59 "Code-MRAM" p 3541 sites the window.

Invariant
k_ra8_dfu_slot_a_base + k_ra8_dfu_slot_size == k_ra8_dfu_slot_b_base.
k_ra8_dfu_slot_b_base + k_ra8_dfu_slot_size == k_ra8_dfu_mram_base + k_ra8_dfu_mram_size.
Enumerator
k_ra8_dfu_mram_base 

Code-MRAM window base.

k_ra8_dfu_mram_size 

Code-MRAM window size (1 MiB).

k_ra8_dfu_bl_size 

Immutable bootloader size (128K).

k_ra8_dfu_slot_a_base 

Slot A base (app vectors here).

k_ra8_dfu_slot_b_base 

Slot B base (app vectors here).

k_ra8_dfu_slot_size 

Per-slot size (448 KiB).

k_ra8_dfu_page_size 

MRAM program page (32 bytes).

k_ra8_dfu_hdr_size 

Image header size (32 bytes).

k_ra8_dfu_img_max 

Max image bytes (slot - header).

k_ra8_dfu_hdr_offset 

Header offset (slot's last page).

k_ra8_dfu_hdr_magic 

Valid-image header magic ("RA8D").

k_ra8_dfu_trigger_magic 

No-init SRAM DFU-request magic.

Definition at line 94 of file ra8_dfu.h.

◆ ra8_dfu_run_t

enum ra8_dfu_run_t : uint32_t

Fixed SRAM copy-to-run execution base.

On a valid-slot boot the bootloader copies the staged image body out of the slot to this single SRAM address and launches it there, so every payload is linked at exactly this base and one image runs from either slot. The value clears the bootloader's own low-SRAM footprint (< 64 KiB) with margin, and a maximum k_ra8_dfu_img_max image copied here ends well below the bootloader's stack at the top of SRAM – so the copy never clobbers live bootloader state. The payload's linker ORIGIN MUST equal this value.

Invariant
k_ra8_dfu_run_base lies in the 2 MiB SRAM window (0x22000000) and k_ra8_dfu_run_base + k_ra8_dfu_img_max stays inside it.
Enumerator
k_ra8_dfu_run_base 

SRAM copy-to-run / payload link base.

Definition at line 125 of file ra8_dfu.h.

◆ ra8_dfu_slot_t

enum ra8_dfu_slot_t : uint8_t

Application-slot identifier.

Enumerator
k_ra8_dfu_slot_a 

Slot A (0x02020000).

k_ra8_dfu_slot_b 

Slot B (0x02090000).

k_ra8_dfu_slot_none 

No valid slot present.

Definition at line 133 of file ra8_dfu.h.

Function Documentation

◆ ra8_dfu_boot_decide()

ra8_dfu_action_t ra8_dfu_boot_decide ( bool dfu_trigger,
bool a_valid,
uint32_t a_seq,
bool b_valid,
uint32_t b_seq )

Reset-time boot decision: jump to a slot, or enter DFU.

Returns k_ra8_dfu_action_dfu when the no-init DFU trigger is set or when neither slot is valid; otherwise maps ra8_dfu_select_slot onto a jump action. This is the single decision the bootloader's main branches on.

Parameters
[in]dfu_triggertrue iff the no-init SRAM DFU-request magic was set.
[in]a_validSlot A validity (ra8_dfu_hdr_valid result).
[in]a_seqSlot A header sequence number.
[in]b_validSlot B validity (ra8_dfu_hdr_valid result).
[in]b_seqSlot B header sequence number.
Returns
The action the bootloader should take.
Return values
k_ra8_dfu_action_dfuTrigger set, or no valid slot.
k_ra8_dfu_action_jump_aBoot Slot A.
k_ra8_dfu_action_jump_bBoot Slot B.
Precondition
Validity flags came from ra8_dfu_hdr_valid on the live headers.
dfu_trigger reflects the one-shot no-init magic read at reset.
Postcondition
No state is mutated.
The returned action is always a defined ra8_dfu_action_t value.
Note
Thread-safe (pure). Compound decision – MC/DC vectors in the test.
See also
ra8_dfu_select_slot
Since
0.1.0

Definition at line 87 of file ra8_dfu_boot.c.

References k_ra8_dfu_action_dfu, k_ra8_dfu_action_jump_a, k_ra8_dfu_action_jump_b, k_ra8_dfu_slot_a, k_ra8_dfu_slot_b, and ra8_dfu_select_slot().

Referenced by blc_decide().

◆ ra8_dfu_crc32()

uint32_t ra8_dfu_crc32 ( const uint8_t * data,
uint32_t len )

Compute the IEEE-802.3 CRC32 of a byte range (software).

Standard reflected CRC32 (poly 0xEDB88320, init 0xFFFFFFFF, final XOR 0xFFFFFFFF) – the same value crc32/zlib produce, so a host tool can pre-compute the header img_crc32. Pure and bounded: one pass over len bytes, no table state retained between calls.

Parameters
[in]dataSource bytes; may be NULL only when len == 0.
[in]lenNumber of bytes to fold in.
Returns
The 32-bit CRC of data[0 .. len); 0 of an empty range folds to 0x00000000 (init ^ final over zero bytes).
Return values
0x00000000Empty range (len == 0); init XOR final over zero bytes.
Precondition
data != NULL whenever len > 0.
len does not exceed the addressable image (caller-checked).
Postcondition
No state is mutated; the result depends only on the inputs.
The polynomial accumulator is not retained between calls (stateless).
Note
Thread-safe and reentrant (no statics).
See also
ra8_dfu_hdr_valid
Since
0.1.0

Compute the IEEE-802.3 CRC32 of a byte range (software).

Definition at line 38 of file ra8_dfu_boot.c.

References k_ra8_dfu_crc_bits, k_ra8_dfu_crc_init, k_ra8_dfu_crc_lsb, k_ra8_dfu_crc_poly, and k_ra8_dfu_crc_xout.

Referenced by ra8_dfu_program_commit(), and ra8_dfu_slot_valid().

◆ ra8_dfu_hdr_valid()

bool ra8_dfu_hdr_valid ( const ra8_dfu_img_hdr_t * hdr,
uint32_t computed_crc )

Decide whether a slot header describes a valid bootable image.

A header is valid iff the magic matches, the length is a non-zero multiple of the 32-byte page within [k_ra8_dfu_page_size, k_ra8_dfu_img_max], and the supplied freshly-computed CRC equals the stored img_crc32. The caller computes computed_crc over the live slot image (ra8_dfu_crc32) before calling, so this function stays pure and host-testable.

Parameters
[in]hdrHeader to test (may be NULL -> invalid).
[in]computed_crcCRC32 the caller computed over the image body.
Returns
true iff the header + CRC describe a valid image.
Return values
trueMagic, length bounds/alignment, and CRC all pass.
falsehdr is NULL, or any check fails.
Precondition
computed_crc was produced by ra8_dfu_crc32 over exactly hdr->img_len bytes of the slot's image body.
The slot's image body is readable when the caller computes the CRC.
Postcondition
No state is mutated.
The caller's hdr pointer and computed_crc value are not modified.
Note
Thread-safe (pure). Carries compound boolean decisions – see the @par MC/DC: block in tests/misc/src/test_ra8_dfu_boot.c.
See also
ra8_dfu_select_slot
Since
0.1.0

Definition at line 55 of file ra8_dfu_boot.c.

References ra8_dfu_img_hdr_t::img_crc32, ra8_dfu_img_hdr_t::img_len, k_ra8_dfu_hdr_magic, k_ra8_dfu_img_max, k_ra8_dfu_page_size, and ra8_dfu_img_hdr_t::magic.

Referenced by ra8_dfu_slot_valid().

◆ ra8_dfu_launch()

void ra8_dfu_launch ( uintptr_t src,
uint32_t img_len,
uint32_t entry )

Copy an image to the SRAM run base and branch to it (copy-to-run).

The shared copy-to-run hand-off (firmware only): validates entry / img_len with ra8_dfu_run_target_valid, copies img_len bytes from src to the trusted k_ra8_dfu_run_base, then sets the Secure VTOR to the run base, loads the image's initial MSP, and branches to its reset vector. Used by the dfu_bootloader (launching a slot body) and the dfu_copy_to_run HIL demo (launching an embedded image). The copy destination is always the run-base constant, never entry, so a corrupted entry cannot redirect it.

Interrupts are masked across the copy and switch; the launched image re-enables them after its own bring-up. Under RA8_OFF_TARGET the branch is elided (a host cannot reset MSP/VTOR), so the function validates and returns.

Parameters
[in]srcSource image base (image body, vector table first); non-zero.
[in]img_lenImage body length in bytes; a non-zero 32-byte multiple.
[in]entryThe image's recorded run base; must equal k_ra8_dfu_run_base.
Returns
void – returns to the caller ONLY when the inputs fail validation (src == 0, or ra8_dfu_run_target_valid is false); on a valid image it does not return (control passes to the image).
Precondition
src points at a readable image whose first two words are MSP + reset.
The image was linked at k_ra8_dfu_run_base; the caller masks nothing special (this masks IRQs itself).
Postcondition
On a valid image, control is at the image's reset vector with VTOR / MSP pointing at the run base.
On invalid inputs, no copy or branch happens and control returns.
Note
Firmware only (inline MSP/VTOR/branch); not thread-safe.
See also
ra8_dfu_run_target_valid
Since
0.1.0

Definition at line 97 of file ra8_dfu_launch.c.

References k_ra8_dfu_run_base, ra8_dfu_run_target_valid(), and ra8_scb_set_vtor().

Referenced by blc_boot_slot(), main(), and sb_tampered_rejected().

◆ ra8_dfu_other_slot()

ra8_dfu_slot_t ra8_dfu_other_slot ( ra8_dfu_slot_t slot)

Return the opposite slot (A<->B).

Inverts the slot identifier: Slot A returns Slot B and any other value (Slot B or k_ra8_dfu_slot_none) returns Slot A. Used by the DFU device and host glue to locate the inactive (write-target) slot when the active slot is known. Passing k_ra8_dfu_slot_none returns k_ra8_dfu_slot_a by the else branch, consistent with "no preference -> start with A".

Parameters
[in]slotSlot identifier (A or B).
Returns
The complementary slot identifier.
Return values
k_ra8_dfu_slot_bInput was k_ra8_dfu_slot_a.
k_ra8_dfu_slot_aInput was k_ra8_dfu_slot_b or k_ra8_dfu_slot_none.
Precondition
slot is a defined ra8_dfu_slot_t value.
The caller understands that k_ra8_dfu_slot_none maps to k_ra8_dfu_slot_a (not a programming error; see details above).
Postcondition
No state is mutated.
The returned slot is always either k_ra8_dfu_slot_a or k_ra8_dfu_slot_b (never k_ra8_dfu_slot_none).
Note
Thread-safe (pure; no statics).
Since
0.1.0

Definition at line 117 of file ra8_dfu_program.c.

References k_ra8_dfu_slot_a, and k_ra8_dfu_slot_b.

Referenced by blc_decide().

◆ ra8_dfu_program_commit()

ra8_err_t ra8_dfu_program_commit ( ra8_dfu_slot_t inactive,
uint32_t img_len,
uint32_t seq )
nodiscard

Finalize a slot: CRC the programmed body, then program the header.

Folds ra8_dfu_crc32 over the just-programmed body in MRAM, builds a ra8_dfu_img_hdr_t (magic, the given seq, img_len, that CRC, and entry = k_ra8_dfu_run_base), and programs the 32-byte header LAST into the slot's last page. After this the slot is bootable; a power loss before the header lands leaves the slot header erased (invalid) – never half-valid.

Parameters
[in]inactiveSlot being committed.
[in]img_lenTotal image-body length programmed; 32-byte multiple.
[in]seqSequence number to stamp (caller uses other-slot seq + 1).
Returns
ra8_err_t outcome.
Return values
k_ra8_okHeader programmed; slot now valid.
k_ra8_err_invalid_arginactive none/invalid or img_len out of range.
k_ra8_err_hw_errorController reported a program error.
Precondition
All body chunks for inactive were programmed via ra8_dfu_program_image.
img_len is a non-zero 32-byte multiple <= k_ra8_dfu_img_max.
Postcondition
On success ra8_dfu_slot_valid(inactive) is true.
Note
Not thread-safe; SRAM-resident on firmware.
Since
0.1.0

Definition at line 226 of file ra8_dfu_program.c.

References ra8_dfu_img_hdr_t::entry, ra8_dfu_img_hdr_t::img_crc32, ra8_dfu_img_hdr_t::img_len, k_ra8_dfu_hdr_magic, k_ra8_dfu_hdr_offset, k_ra8_dfu_hdr_size, k_ra8_dfu_img_max, k_ra8_dfu_page_size, k_ra8_dfu_run_base, k_ra8_err_invalid_arg, ra8_dfu_img_hdr_t::magic, priv_dfu_write_secure(), ra8_dfu_crc32(), ra8_dfu_slot_base(), and ra8_dfu_img_hdr_t::seq.

◆ ra8_dfu_program_image()

ra8_err_t ra8_dfu_program_image ( ra8_dfu_slot_t inactive,
uint32_t img_offset,
const uint8_t * data,
uint32_t len )
nodiscard

Program one image chunk into the inactive slot's body.

Writes len bytes at slot_base + img_offset through the SECURE MRAM gate (k_ra8_flash_world_s). Each 32-byte page is erased to 0xFF then programmed, IRQ-masked, by the SRAM-resident internal_write_secure (ra8_dfu_program.c). The header page (the slot's last page, at slot_base + k_ra8_dfu_hdr_offset) is left untouched until ra8_dfu_program_commit, so a torn download never leaves a valid-looking header over a partial image.

Parameters
[in]inactiveSlot being programmed (must match ra8_dfu_program_prepare).
[in]img_offsetByte offset into the image body; 32-byte aligned.
[in]dataSource bytes (non-NULL).
[in]lenLength in bytes; non-zero multiple of k_ra8_dfu_page_size.
Returns
ra8_err_t outcome.
Return values
k_ra8_okChunk programmed.
k_ra8_err_null_ptrdata is NULL.
k_ra8_err_invalid_arginactive none/invalid, bad alignment, or the chunk would exceed k_ra8_dfu_img_max.
k_ra8_err_out_of_rangeThe access window rejected the address.
k_ra8_err_hw_errorController reported a program error.
Precondition
ra8_dfu_program_prepare ran for inactive; data non-NULL.
img_offset and len are 32-byte multiples; img_offset + len <= img_max.
Postcondition
On success the chunk holds data; the program gate is locked.
Note
Not thread-safe; SRAM-resident on firmware.
Since
0.1.0

Definition at line 203 of file ra8_dfu_program.c.

References k_ra8_dfu_img_max, k_ra8_dfu_page_size, k_ra8_err_invalid_arg, k_ra8_err_null_ptr, priv_dfu_write_secure(), and ra8_dfu_slot_base().

◆ ra8_dfu_program_prepare()

ra8_err_t ra8_dfu_program_prepare ( ra8_dfu_slot_t inactive)
nodiscard

Open ra8_flash and fence all writes to one slot's window.

Opens the MRAM controller (ra8_flash_open) and sets the software access window (ra8_flash_set_window) to exactly the inactive slot so any stray write outside it is rejected. It does NOT erase: there is no full-slot erase (which would block USB long enough to time out the host's DFU_GETSTATUS), and no header pre-erase either. Instead ra8_dfu_program_image erases each 32-byte page to 0xFF immediately before programming its body, and ra8_dfu_program_commit writes the header LAST – so a torn download leaves the OLD header over a NEW partial image, whose CRC will not match -> invalid. Brick defense: the bootloader region and the active slot are outside the window and untouchable.

Parameters
[in]inactiveThe slot to (re)program (A or B; must NOT be the running one).
Returns
ra8_err_t outcome.
Return values
k_ra8_okSlot opened and the write window fenced to it.
k_ra8_err_invalid_arginactive is none/invalid.
k_ra8_err_hw_errorController bring-up reported an error.
Precondition
inactive is A or B and is not the slot the caller is executing from.
Caller runs from SRAM (firmware) – the program loop must not be in MRAM.
Postcondition
On success the access window is exactly [slot_base, slot_base + size).
The MRAM program-control gate is locked on every exit path.
Note
Not thread-safe; single programmer.
Since
0.1.0

Definition at line 181 of file ra8_dfu_program.c.

References k_ra8_dfu_slot_size, k_ra8_err_invalid_arg, k_ra8_ok, ra8_dfu_slot_base(), ra8_flash_open(), ra8_flash_set_window(), and s_ra8_dfu_flash_cfg.

◆ ra8_dfu_program_verify()

ra8_err_t ra8_dfu_program_verify ( ra8_dfu_slot_t slot)
nodiscard

Read-back verify: re-CRC a slot's body against its stored header.

Parameters
[in]slotSlot to verify (A or B).
Returns
ra8_err_t outcome.
Return values
k_ra8_okHeader valid and the body CRC matches.
k_ra8_err_invalid_argslot is none/invalid.
k_ra8_err_crc_mismatchHeader invalid or the recomputed CRC differs.
Precondition
slot is A or B; the MRAM window is readable.
Postcondition
No MRAM mutated.
Note
Independent of ra8_dfu_program_commit's in-flight CRC.
Since
0.1.0

Definition at line 252 of file ra8_dfu_program.c.

References k_ra8_err_crc_mismatch, k_ra8_err_invalid_arg, k_ra8_ok, ra8_dfu_slot_base(), and ra8_dfu_slot_valid().

◆ ra8_dfu_read_header()

ra8_err_t ra8_dfu_read_header ( ra8_dfu_slot_t slot,
ra8_dfu_img_hdr_t * out_hdr )
nodiscard

Copy a slot's 32-byte header out of MRAM.

Parameters
[in]slotSlot to read (A or B).
[out]out_hdrDestination header (non-NULL).
Returns
ra8_err_t outcome.
Return values
k_ra8_okHeader copied.
k_ra8_err_invalid_argslot is none/invalid.
k_ra8_err_null_ptrout_hdr is NULL.
Precondition
out_hdr non-NULL; slot is A or B.
The MRAM window is readable (always true post-reset / off-target).
Postcondition
*out_hdr holds the slot's first 32 bytes; no MRAM mutated.
Note
Not thread-safe vs a concurrent program of the same slot.
Since
0.1.0

Definition at line 122 of file ra8_dfu_program.c.

References k_ra8_dfu_hdr_offset, k_ra8_err_invalid_arg, k_ra8_err_null_ptr, k_ra8_ok, memcpy(), and ra8_dfu_slot_base().

Referenced by blc_boot_slot(), ra8_dfu_slot_seq(), and ra8_dfu_slot_valid().

◆ ra8_dfu_run_target_valid()

bool ra8_dfu_run_target_valid ( uint32_t entry,
uint32_t img_len )

Decide whether a validated slot's image may be copied-to-run.

The boot-time cross-check before the bootloader copies a slot body to SRAM and launches it: the header's entry must be the fixed k_ra8_dfu_run_base (so the image was linked for the run base, and a corrupted entry is caught), and img_len must be a non-zero 32-byte multiple within [k_ra8_dfu_page_size, k_ra8_dfu_img_max] (so the copy length is sane and the image fits the SRAM run window). Pure – the bootloader still copies to the trusted k_ra8_dfu_run_base constant, never to entry itself.

Parameters
[in]entryThe candidate image's header entry field.
[in]img_lenThe candidate image's body length, bytes.
Returns
true iff the image may be copied to k_ra8_dfu_run_base and run.
Return values
trueentry == k_ra8_dfu_run_base and img_len is in range/aligned.
falseentry is not the run base, or img_len is zero / too large / not a 32-byte multiple.
Precondition
entry and img_len are the live header fields of a slot that already passed ra8_dfu_hdr_valid (magic + length + body CRC).
Neither entry nor img_len is taken from an untrusted external source without a prior ra8_dfu_hdr_valid check.
Postcondition
No state is mutated.
The bootloader never uses entry as the copy destination; this function only validates it against the trusted k_ra8_dfu_run_base.
Note
Thread-safe (pure). Compound decision – MC/DC vectors in the test.
See also
ra8_dfu_hdr_valid
Since
0.1.0

Definition at line 67 of file ra8_dfu_boot.c.

References k_ra8_dfu_img_max, k_ra8_dfu_page_size, and k_ra8_dfu_run_base.

Referenced by ra8_dfu_launch().

◆ ra8_dfu_select_slot()

ra8_dfu_slot_t ra8_dfu_select_slot ( bool a_valid,
uint32_t a_seq,
bool b_valid,
uint32_t b_seq )

Pick the active slot from the two slots' validity + sequence.

The valid slot with the higher sequence number wins; Slot A wins a tie (deterministic). If only one slot is valid, it wins; if neither is valid, k_ra8_dfu_slot_none is returned so the caller enters DFU.

Parameters
[in]a_validtrue iff Slot A passed ra8_dfu_hdr_valid.
[in]a_seqSlot A header sequence number.
[in]b_validtrue iff Slot B passed ra8_dfu_hdr_valid.
[in]b_seqSlot B header sequence number.
Returns
The selected slot, or k_ra8_dfu_slot_none.
Return values
k_ra8_dfu_slot_aA valid and (B invalid or a_seq >= b_seq).
k_ra8_dfu_slot_bB valid and (A invalid or b_seq > a_seq).
k_ra8_dfu_slot_noneNeither slot valid.
Precondition
a_valid / b_valid reflect a prior ra8_dfu_hdr_valid result.
a_seq / b_seq are the live header sequence values.
Postcondition
No state is mutated.
The returned slot identifier is always a defined ra8_dfu_slot_t value.
Note
Thread-safe (pure). Compound decision – MC/DC vectors in the test.
See also
ra8_dfu_boot_decide
Since
0.1.0

Definition at line 75 of file ra8_dfu_boot.c.

References k_ra8_dfu_slot_a, k_ra8_dfu_slot_b, and k_ra8_dfu_slot_none.

Referenced by blc_decide(), and ra8_dfu_boot_decide().

◆ ra8_dfu_slot_base()

uintptr_t ra8_dfu_slot_base ( ra8_dfu_slot_t slot)

Return the MRAM base address of a slot.

Maps the ra8_dfu_slot_t identifier to its fixed MRAM window start address. Slot A maps to k_ra8_dfu_slot_a_base and Slot B maps to k_ra8_dfu_slot_b_base. Returns 0 for k_ra8_dfu_slot_none or any out-of-range value so callers can detect the sentinel without a separate validity test.

Parameters
[in]slotSlot identifier.
Returns
The slot base address, or 0 for k_ra8_dfu_slot_none / an invalid id.
Return values
k_ra8_dfu_slot_a_baseSlot A (slot == k_ra8_dfu_slot_a).
k_ra8_dfu_slot_b_baseSlot B (slot == k_ra8_dfu_slot_b).
0slot is k_ra8_dfu_slot_none or out of range.
Precondition
slot is a defined ra8_dfu_slot_t value.
The caller does not pass a raw integer that has not been validated as a ra8_dfu_slot_t member.
Postcondition
No state is mutated.
The returned address, when non-zero, lies within the MRAM window [k_ra8_dfu_mram_base, k_ra8_dfu_mram_base + k_ra8_dfu_mram_size).
Note
Thread-safe (pure; no statics).
Since
0.1.0

Definition at line 99 of file ra8_dfu_program.c.

References k_ra8_dfu_slot_a, k_ra8_dfu_slot_a_base, k_ra8_dfu_slot_b, k_ra8_dfu_slot_b_base, and k_ra8_dfu_slot_none.

Referenced by blc_boot_slot(), ra8_dfu_program_commit(), ra8_dfu_program_image(), ra8_dfu_program_prepare(), ra8_dfu_program_verify(), ra8_dfu_read_header(), and ra8_dfu_slot_valid().

◆ ra8_dfu_slot_seq()

ra8_err_t ra8_dfu_slot_seq ( ra8_dfu_slot_t slot,
uint32_t * out_seq )
nodiscard

Read a slot header's sequence number (0 if the magic is wrong).

Parameters
[in]slotSlot to read (A or B).
[out]out_seqDestination sequence (non-NULL); 0 when magic mismatches.
Returns
ra8_err_t outcome.
Return values
k_ra8_ok*out_seq populated (0 if header magic wrong).
k_ra8_err_invalid_argslot is none/invalid.
k_ra8_err_null_ptrout_seq is NULL.
Precondition
out_seq non-NULL; slot is A or B.
Postcondition
No MRAM mutated.
Note
Used to pick the next monotonic seq (other-slot seq + 1).
Since
0.1.0

Definition at line 167 of file ra8_dfu_program.c.

References k_ra8_dfu_hdr_magic, k_ra8_err_null_ptr, k_ra8_ok, ra8_dfu_img_hdr_t::magic, ra8_dfu_read_header(), and ra8_dfu_img_hdr_t::seq.

Referenced by blc_decide().

◆ ra8_dfu_slot_valid()

bool ra8_dfu_slot_valid ( ra8_dfu_slot_t slot)

Validate a slot live: header magic/length/CRC over its real image.

Reads the slot header, then folds ra8_dfu_crc32 over the live image body in MRAM and applies ra8_dfu_hdr_valid.

Parameters
[in]slotSlot to validate (A or B).
Returns
true iff the slot holds a valid bootable image.
Return values
trueHeader + image CRC pass.
falseslot is none/invalid, or any check fails.
Precondition
slot is A or B; the MRAM window is readable.
The caller has not concurrently issued a program operation to the same slot (read-only – not thread-safe vs a concurrent writer).
Postcondition
No MRAM is mutated.
The function result accurately reflects the slot state at the time of the call; a concurrent write may invalidate it immediately after.
Note
Reads up to img_len bytes of MRAM; not thread-safe vs a writer.
Since
0.1.0

Validate a slot live: header magic/length/CRC over its real image.

Definition at line 142 of file ra8_dfu_program.c.

References ra8_dfu_img_hdr_t::img_len, k_ra8_dfu_img_max, k_ra8_dfu_page_size, k_ra8_ok, ra8_dfu_crc32(), ra8_dfu_hdr_valid(), ra8_dfu_read_header(), and ra8_dfu_slot_base().

Referenced by blc_decide(), dfu_host_pass(), and ra8_dfu_program_verify().