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

Cortex-M85 CPU exception diagnostic helpers. More...

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

Go to the source code of this file.

Data Structures

struct  ra8_exception_frame_t
 Stacked registers pushed by the Cortex-M exception entry. More...
struct  ra8_exception_diagnostics_t
 SCB fault-status register snapshot. More...
struct  ra8_exception_last_t
 Fixed-SRAM post-mortem snapshot of the most recent fault or NMI. More...

Typedefs

typedef void(* ra8_exception_persist_fn) (const volatile ra8_exception_last_t *decoded)
 Post-decode persistence sink invoked once the snapshot is complete.

Enumerations

enum  ra8_exception_magic_t : uint32_t { k_ra8_exc_magic_valid = 0xFA17DEADUL }
 Sentinel marking a fully-written g_ra8_exception_last snapshot. More...

Functions

void ra8_exception_set_persist_hook (ra8_exception_persist_fn hook)
 Register (or clear) the post-decode fault-persistence hook.
void ra8_exception_capture_diagnostics (ra8_exception_diagnostics_t *out)
 Read the current SCB fault-status registers.
void ra8_exception_report (const ra8_exception_frame_t *frame, uint32_t exc_number)
 Emit a full fault dump over the log backend.
void ra8_exception_report_nmi (const ra8_exception_frame_t *frame, uint32_t nmisr)
 Report an NMI with its ICU cause register, then halt.

Variables

volatile ra8_exception_last_t g_ra8_exception_last
 The one fixed-SRAM ra8_exception_last_t snapshot instance.

Detailed Description

Cortex-M85 CPU exception diagnostic helpers.

When the Cortex-M85 takes a HardFault / MemManage / BusFault / UsageFault / SecureFault, the default Default_Handler in src/boot/vector_table.c drops into BKPT #0. That is fine for an attached J-Link but useless for a field deployment.

This module provides richer fault handlers that:

  1. Decode the stacked exception frame (r0..r3, r12, lr, pc, xpsr) into an ra8_exception_frame_t struct.
  2. Read the System Control Block fault-status registers (CFSR, HFSR, DFSR, BFAR, MMFAR, AFSR, plus the TrustZone SFSR / SFAR pair) and populate an ra8_exception_diagnostics_t.
  3. Emit a single log line summarising the fault.
  4. Call ra8_fatal_error() to halt.

The same record path serves the RA8D2 NMI: the board-layer NMI handler reads the ICU's NMISR cause register and forwards it here via ra8_exception_report_nmi(), so a watchdog underflow, an SRAM ECC error, or an LVD trip leaves the same debugger-readable snapshot as a CPU fault instead of a bare bkpt trap.

The intent is that if a field unit ever takes a HardFault, the user plugs in a J-Link, attaches, and can read the stack frame + CFSR bits from the log backend ring buffer instead of having to reproduce the fault in a debugger session.

Definition in file ra8_exception.h.

Typedef Documentation

◆ ra8_exception_persist_fn

typedef void(* ra8_exception_persist_fn) (const volatile ra8_exception_last_t *decoded)

Post-decode persistence sink invoked once the snapshot is complete.

ra8_exception_report() calls the registered hook (if any) AFTER g_ra8_exception_last is fully populated and its magic is set, but BEFORE the CPU halts. It is the Dependency-Inversion seam the crash-log layer (ra8_crashlog_install()) plugs into to copy the decoded record into cross-reset .noinit storage. The pointer defaults to nullptr (no persistence), so an app that never installs a hook pays nothing and pulls in no crash-log code.

Parameters
[in]decodedThe completed fixed-SRAM snapshot (never nullptr; always &g_ra8_exception_last).
See also
ra8_exception_set_persist_hook()
Since
0.1.0

Definition at line 178 of file ra8_exception.h.

Enumeration Type Documentation

◆ ra8_exception_magic_t

enum ra8_exception_magic_t : uint32_t

Sentinel marking a fully-written g_ra8_exception_last snapshot.

magic is written LAST when the snapshot is complete, so a debugger (or a post-mortem reader) can distinguish a full record from a half-written one interrupted by a secondary fault.

See also
g_ra8_exception_last
Since
0.1.0
Enumerator
k_ra8_exc_magic_valid 

Snapshot is fully populated.

Definition at line 102 of file ra8_exception.h.

Function Documentation

◆ ra8_exception_capture_diagnostics()

void ra8_exception_capture_diagnostics ( ra8_exception_diagnostics_t * out)

Read the current SCB fault-status registers.

Parameters
[out]outPointer to a buffer to fill. Must not be nullptr.

See implementation for details.

Precondition
Module has been initialized.
Caller has validated arguments.
Postcondition
Side effects bounded to documented state.
State reflects operation result.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Read the current SCB fault-status registers.

Delegates the CFSR / HFSR / DFSR / MMFAR / BFAR / AFSR + Secure SFSR / SFAR reads to ra8_scb_read_fault_status, then copies the snapshot into the exception-record layout. NULL argument is tolerated and returns silently (the fault path must never log from here), so the shared primitive is only ever handed a stack local and its null-guard return cannot trip. Behaviourally identical to the previous inline reads: the same eight registers in the same order, no register written.

Parameters
[out]outDestination buffer. May be nullptr.
Precondition
out is either nullptr or points to writable storage.
SCB MMIO at 0xE000ED00 is accessible.
Postcondition
On non-nullptr input, every field of *out reflects the SCB at the moment of the call.
No SCB register is modified.
Note
Not reentrant w.r.t. concurrent SCB writes.
Since
0.1.0

Definition at line 94 of file ra8_exception.c.

References ra8_exception_diagnostics_t::afsr, ra8_scb_fault_status_t::afsr, ra8_exception_diagnostics_t::bfar, ra8_scb_fault_status_t::bfar, ra8_exception_diagnostics_t::cfsr, ra8_scb_fault_status_t::cfsr, ra8_exception_diagnostics_t::dfsr, ra8_scb_fault_status_t::dfsr, ra8_exception_diagnostics_t::hfsr, ra8_scb_fault_status_t::hfsr, k_ra8_ok, ra8_exception_diagnostics_t::mmfar, ra8_scb_fault_status_t::mmfar, ra8_scb_read_fault_status(), ra8_exception_diagnostics_t::sfar, ra8_scb_fault_status_t::sfar, ra8_exception_diagnostics_t::sfsr, and ra8_scb_fault_status_t::sfsr.

Referenced by ra8_exception_report().

◆ ra8_exception_report()

void ra8_exception_report ( const ra8_exception_frame_t * frame,
uint32_t exc_number )

Emit a full fault dump over the log backend.

Logs the exception frame + diagnostics at ERROR level, then calls ra8_fatal_error() which halts. Meant to be called from a naked assembly trampoline installed in place of the weak HardFault_Handler alias – see the example in ra8_exception.c.

Parameters
[in]framePointer to stacked exception frame.
[in]exc_numberException number (2 = NMI, 3 = HardFault, ..., 7 = SecureFault).

Emit a full fault dump over the log backend.

Captures the stacked frame and SCB diagnostics into the fixed-SRAM snapshot g_ra8_exception_last BEFORE any function call that might itself fault. Then best-effort logs them via internal_log_fault_dump (ra8_log silently drops every byte from a fault context on the default ITM backend; a registered byte sink still emits, see libs/ra8_core/src/ra8_log.c). Finally parks the CPU at the named internal_exception_halt_loop symbol on target so the debugger can give the halt a clean backtrace instead of escalating to LOCKUP at PC=0xEFFFFFFE.

Parameters
[in]frameStacked exception frame; may be nullptr.
[in]exc_numberArchitectural exception number.
Precondition
Invoked from a fault context (IPSR != 0).
g_ra8_exception_last is writable SRAM.
Postcondition
g_ra8_exception_last.magic == 0xFA17DEAD once snapshot is complete.
Control never returns; CPU is halted at a named symbol.
Note
Marked noreturn. Not thread-safe.
Since
0.1.0

Definition at line 270 of file ra8_exception.c.

References g_ra8_exception_last, internal_log_fault_dump(), k_ra8_exc_magic_valid, ra8_exception_frame_t::lr, ra8_exception_frame_t::pc, ra8_exception_frame_t::r0, ra8_exception_frame_t::r1, ra8_exception_frame_t::r12, ra8_exception_frame_t::r2, ra8_exception_frame_t::r3, ra8_exception_capture_diagnostics(), RA8_EXCEPTION_HALT, s_ra8_exception_nmi_stage, s_ra8_exception_persist, and ra8_exception_frame_t::xpsr.

Referenced by blc_fault_dispatch(), and ra8_exception_report_nmi().

◆ ra8_exception_report_nmi()

void ra8_exception_report_nmi ( const ra8_exception_frame_t * frame,
uint32_t nmisr )

Report an NMI with its ICU cause register, then halt.

The RA8D2 routes its non-maskable sources (IWDT/WDT underflow, LVD voltage monitors, oscillation-stop, the NMI pin, bus / SRAM-ECC / MRAM read errors, CPU lockup, FPU exception, IPC) through the ICU, which latches the cause in NMISR. The board-layer NMI_Handler reads NMISR (the register lives in the ICU, outside this core module's ARM-only scope) and forwards it here. The value is staged into the fixed-SRAM snapshot's nmisr field, logged as nmisr=, and the common ra8_exception_report() path then captures the frame

  • SCB diagnostics and halts. Exception number 2 (NMI) is implied.
Parameters
[in]framePointer to the stacked exception frame the NMI pushed (MSP or PSP resident); may be nullptr.
[in]nmisrRaw ICU NMISR value read by the caller. Any uint32 is accepted; bits [31:21], [19] and [11:8] are reserved-as-zero on RA8D2.
Returns
Never returns.
Precondition
Invoked from the NMI handler (or a host test standing in for it).
g_ra8_exception_last is writable SRAM.
Postcondition
g_ra8_exception_last.nmisr holds nmisr and g_ra8_exception_last.exc_number == 2.
Control never returns; the CPU halts at a named symbol (on the host test build, via the overridable fatal hook).
Note
Not thread-safe (single fault context by construction).
// Board-layer NMI handler body:
const uint32_t nmisr = *ra8_icu_nmisr();
void ra8_exception_report_nmi(const ra8_exception_frame_t *frame, uint32_t nmisr)
Report an NMI with its ICU cause register, then halt.
static volatile uint32_t * ra8_icu_nmisr(void)
Get pointer to the 32-bit NMISR register.
See also
ra8_exception_report() The common capture + halt path.
g_ra8_exception_last Where the cause is recorded.
Since
0.1.0

Report an NMI with its ICU cause register, then halt.

Definition at line 322 of file ra8_exception.c.

References k_ra8_exc_num_nmi, ra8_exception_report(), and s_ra8_exception_nmi_stage.

Referenced by internal_nmi_report(), and internal_ra8_board_nmi_report().

◆ ra8_exception_set_persist_hook()

void ra8_exception_set_persist_hook ( ra8_exception_persist_fn hook)

Register (or clear) the post-decode fault-persistence hook.

Installs the ra8_exception_persist_fn that ra8_exception_report() calls once the snapshot is complete. Passing nullptr disarms persistence. The hook runs in fault context, so it must touch nothing that can itself fault (no unpowered peripheral, no dynamic allocation) – copying the snapshot into plain SRAM is the intended use.

Parameters
[in]hookPersistence sink, or nullptr to disable.
Returns
Nothing.
Precondition
Called from single-threaded boot context.
hook, if non-nullptr, is fault-context safe.
Postcondition
ra8_exception_report() invokes hook (or none if nullptr).
No fault snapshot is altered by the registration itself.
Note
Not thread-safe; arm once during boot before faults can occur.
See also
ra8_exception_report()
Since
0.1.0

Register (or clear) the post-decode fault-persistence hook.

Definition at line 155 of file ra8_exception.c.

References s_ra8_exception_persist.

Referenced by ra8_crashlog_install().

Variable Documentation

◆ g_ra8_exception_last

volatile ra8_exception_last_t g_ra8_exception_last
extern

The one fixed-SRAM ra8_exception_last_t snapshot instance.

Lives at a linker-stable address so a J-Link attach after a field fault can read it by symbol name with zero code running.

Note
Volatile so the compiler never elides the capture writes.
Warning
Written only by ra8_exception_report(); treat as read-only everywhere else (tests read it to assert capture contents).
Since
0.1.0

The one fixed-SRAM ra8_exception_last_t snapshot instance.

Definition at line 114 of file ra8_exception.c.

Referenced by ra8_exception_report().