|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
Cortex-M85 CPU exception diagnostic helpers. More...
#include <stdint.h>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. | |
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:
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 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.
| [in] | decoded | The completed fixed-SRAM snapshot (never nullptr; always &g_ra8_exception_last). |
Definition at line 178 of file ra8_exception.h.
| 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.
| Enumerator | |
|---|---|
| k_ra8_exc_magic_valid | Snapshot is fully populated. |
Definition at line 102 of file ra8_exception.h.
| void ra8_exception_capture_diagnostics | ( | ra8_exception_diagnostics_t * | out | ) |
Read the current SCB fault-status registers.
| [out] | out | Pointer to a buffer to fill. Must not be nullptr. |
See implementation for details.
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.
| [out] | out | Destination buffer. May be nullptr. |
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().
| 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.
| [in] | frame | Pointer to stacked exception frame. |
| [in] | exc_number | Exception 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.
| [in] | frame | Stacked exception frame; may be nullptr. |
| [in] | exc_number | Architectural exception number. |
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().
| 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
| [in] | frame | Pointer to the stacked exception frame the NMI pushed (MSP or PSP resident); may be nullptr. |
| [in] | nmisr | Raw ICU NMISR value read by the caller. Any uint32 is accepted; bits [31:21], [19] and [11:8] are reserved-as-zero on RA8D2. |
nmisr and g_ra8_exception_last.exc_number == 2. 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().
| 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.
| [in] | hook | Persistence sink, or nullptr to disable. |
hook, if non-nullptr, is fault-context safe. hook (or none if nullptr). 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().
|
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.
The one fixed-SRAM ra8_exception_last_t snapshot instance.
Definition at line 114 of file ra8_exception.c.
Referenced by ra8_exception_report().