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

MRAM slot program / verify for the USB-DFU bootloader core. More...

#include <string.h>
#include "ra8_dfu.h"
#include "ra8_dfu_internal.h"
#include "ra8_flash.h"
#include "ra8_register_guard.h"
Include dependency graph for ra8_dfu_program.c:

Go to the source code of this file.

Enumerations

enum  ra8_dfu_prog_cfg_t : uint16_t {
  k_ra8_dfu_prog_mrcfreq_mhz = 250U ,
  k_ra8_dfu_prog_mrefreq_mhz = 125U
}
 MRAM clock notifications used to (re)open the controller. More...
enum  ra8_dfu_prog_fill_t : uint8_t { k_ra8_dfu_prog_erased_byte = 0xFFU }
 MRAM erased-state fill byte. More...

Functions

ra8_err_t priv_dfu_write_secure (uintptr_t addr, const uint8_t *src, uint32_t len)
 Implementation of priv_dfu_write_secure() – IRQ-masked, page-at-a-time erase-then-program through the secure MRAM gate.
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)
 Implementation of ra8_dfu_slot_valid() – guards the CRC read so a bogus img_len cannot drive an out-of-bounds MRAM fold.
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.

Variables

static const ra8_flash_cfg_t s_ra8_dfu_flash_cfg
 Default controller bring-up descriptor for ra8_dfu_program_prepare.

Detailed Description

MRAM slot program / verify for the USB-DFU bootloader core.

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

Erases, programs, and read-back-verifies the inactive application slot over ra8_flash, and reads slot headers for the boot decision. The MRAM controller's program loop must NOT execute from the MRAM it touches (see ra8_flash.h); on the firmware target each consumer's linker script places this TU and ra8_flash in SRAM. Under RA8_OFF_TARGET the code-MRAM window is backed by fake memory, so the program -> read-back -> verify round-trip is exercised directly by the host unit tests.

Definition in file ra8_dfu_program.c.

Enumeration Type Documentation

◆ ra8_dfu_prog_cfg_t

enum ra8_dfu_prog_cfg_t : uint16_t

MRAM clock notifications used to (re)open the controller.

Mirrors the EK-RA8D2 code/extra MRAM operating clocks the apps advertise via MRCFREQ / MREFREQ (HUM Ch 59.4.3 p 3550).

Enumerator
k_ra8_dfu_prog_mrcfreq_mhz 

Code-MRAM clock notification (MHz).

k_ra8_dfu_prog_mrefreq_mhz 

Extra-MRAM clock notification (MHz).

Definition at line 34 of file ra8_dfu_program.c.

◆ ra8_dfu_prog_fill_t

enum ra8_dfu_prog_fill_t : uint8_t

MRAM erased-state fill byte.

Value every byte holds after an MRAM erase; used to seed the SRAM-resident all-ones page so the erase baseline operand never has to be read out of code-MRAM while the array is busy (see ::internal_write_secure).

Enumerator
k_ra8_dfu_prog_erased_byte 

Erased-state byte for an MRAM page.

Definition at line 46 of file ra8_dfu_program.c.

Function Documentation

◆ priv_dfu_write_secure()

ra8_err_t priv_dfu_write_secure ( uintptr_t addr,
const uint8_t * src,
uint32_t len )

Implementation of priv_dfu_write_secure() – IRQ-masked, page-at-a-time erase-then-program through the secure MRAM gate.

Program len bytes at addr through the SECURE MRAM gate.

Definition at line 61 of file ra8_dfu_program.c.

References k_ra8_dfu_page_size, k_ra8_dfu_prog_erased_byte, k_ra8_err_invalid_arg, k_ra8_flash_world_s, k_ra8_ok, memset(), ra8_flash_write_block(), RA8_PRIV, ra8_register_guard_enter(), and ra8_register_guard_exit().

Referenced by ra8_dfu_program_commit(), and ra8_dfu_program_image().

◆ 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_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)

Implementation of ra8_dfu_slot_valid() – guards the CRC read so a bogus img_len cannot drive an out-of-bounds MRAM fold.

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().

Variable Documentation

◆ s_ra8_dfu_flash_cfg

const ra8_flash_cfg_t s_ra8_dfu_flash_cfg
static
Initial value:
= {
.mrcfreq_mhz = (uint16_t)k_ra8_dfu_prog_mrcfreq_mhz,
.mrefreq_mhz = (uint8_t)k_ra8_dfu_prog_mrefreq_mhz,
.prefetch_en = true,
.ecc_encoder_enable = true,
.ecc_decoder_enable = true,
}
@ k_ra8_dfu_prog_mrefreq_mhz
Extra-MRAM clock notification (MHz).
@ k_ra8_dfu_prog_mrcfreq_mhz
Code-MRAM clock notification (MHz).

Default controller bring-up descriptor for ra8_dfu_program_prepare.

Definition at line 51 of file ra8_dfu_program.c.

Referenced by ra8_dfu_program_prepare().