ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1
45
46#include <stdint.h>
47
48#include "ra8_attributes.h"
49#include "ra8_board_ek_ra8d2.h"
50#include "ra8_boot_entry.h"
51#include "ra8_cgc.h"
52#include "ra8_err.h"
53#include "ra8_isr.h"
54#include "ra8_mpu.h"
55#include "ra8_time.h"
56
65
66typedef enum : uint32_t {
70
72typedef enum : uint8_t {
76
78typedef enum : uint32_t {
82
84typedef enum : uint8_t {
87
89[[gnu::aligned(32)]] static uint8_t s_ro_buffer[k_mpu_simple_region_size] = {};
90
101static volatile uint8_t s_fault_pending = 0U;
102
121volatile uint32_t g_mpu_simple_match = 0U;
122
135volatile uint32_t g_mpu_simple_fault_count = 0U;
136
148{
149 while (1) {
150 __asm__ volatile("wfi");
151 }
152}
153
155static const ra8_mpu_region_t s_regions[] = {
156 {
157 .base = (uintptr_t)s_ro_buffer,
158 .size = (uint32_t)k_mpu_simple_region_size,
159 .priv = k_ra8_mpu_perm_ro,
160 .unpriv = k_ra8_mpu_perm_ro,
161 .executable = false,
162 .shareable = k_ra8_mpu_share_inner,
163 .attr_idx = k_ra8_mpu_attr_idx_0,
164 },
165};
166
168static const ra8_mpu_cfg_t s_cfg = {
169 .regions = s_regions,
170 .region_count = 1U,
171 .mair0 = (uint32_t)k_mpu_simple_mair0_word,
172 .mair1 = 0U,
173 .privdefena = true,
174 .hfnmiena = false,
175};
176
226
258{
260 if (s_ro_buffer[0] == (uint8_t)k_mpu_simple_probe_byte) {
261 return k_ra8_ok;
262 }
263 return k_ra8_err_hw_error;
264}
265
266#ifndef RA8_OFF_TARGET
312/* Non-static + used: the inline assembly in MemManage_Handler
313 * references this symbol by name, so it must survive LTO and the
314 * dead-code stripper. */
315RA8_INTERNAL [[gnu::used]] static void internal_mpu_simple_fault_recover(uint32_t* frame);
316RA8_INTERNAL [[gnu::used]] static void internal_mpu_simple_fault_recover(uint32_t* frame)
317{
318 /* Advance the stacked PC past the faulting store. The compiler
319 * emits ``strb r3, [r2]`` for the probe, which is 16 bits on
320 * Thumb-1 / 32 bits on Thumb-2 depending on register allocation.
321 * Reading the half-word at the stacked PC tells us which one we
322 * landed on: low 5 bits 0b11101/0b11110/0b11111 mark a 32-bit
323 * encoding (Armv8-M ARM A6.3.1 "Thumb instruction set encoding"),
324 * everything else is 16-bit. */
325 const uint16_t* insn = (const uint16_t*)frame[k_mpu_simple_frame_pc_idx];
326 const uint16_t first_halfwd = *insn;
327 const uint16_t hi5 = (uint16_t)((first_halfwd >> k_thumb_hi5_shift) & k_thumb_hi5_mask);
328 const bool is_thumb2_32b = (hi5 == k_thumb2_prefix_11101) || (hi5 == k_thumb2_prefix_11110) ||
329 (hi5 == k_thumb2_prefix_11111);
330 frame[k_mpu_simple_frame_pc_idx] += (is_thumb2_32b ? 4U : 2U);
331
332 /* NOTE: we deliberately do NOT clear the MemManage half-word of
333 * CFSR. The HIL alive-mode probe runs with HIL_FAULT_EXPECTED=1
334 * and explicitly REQUIRES a non-zero CFSR at probe time to prove
335 * the configurable fault actually fired (the failure mode the
336 * flag guards against is "app booted, looped, but never tripped
337 * the MPU because the partition was misconfigured"). Leaving the
338 * MMFSR bits latched gives the probe both proofs: CFSR != 0 says
339 * the fault fired, and the running CycleCnt + match-counter +
340 * UART banner say recovery succeeded. The bits self-clear on the
341 * next chip reset; firmware never reads CFSR. */
343 s_fault_pending = 1U;
344}
345
346[[gnu::naked]] void MemManage_Handler(void);
348{
349 __asm__ volatile("tst lr, #4 \n"
350 "ite eq \n"
351 "mrseq r0, msp \n"
352 "mrsne r0, psp \n"
353 "push {lr} \n"
354 "bl internal_mpu_simple_fault_recover \n"
355 "pop {lr} \n"
356 "bx lr \n");
357}
358#endif /* !RA8_OFF_TARGET */
359
375static const uint8_t s_mpu_simple_banner[] = "mpu: fault handled, recovered\r\n";
376
392
393void main(void)
394{
397
400 }
401
402 /* Probe drives the deliberate fault. On silicon the recovering
403 * handler advances the stacked PC past the offending store and
404 * resumes here; the readback then sees the original 0x00 (handler
405 * skipped the write that would have written 0x42), so the probe
406 * returns k_ra8_err_hw_error. On the host fake the store just
407 * succeeds and the probe returns k_ra8_ok. */
409 /* Host path: MPU did not arm (or fake). Latch LED3 as a
410 * diagnostic but keep the main loop spinning so the HIL probe
411 * sees forward progress. */
413 } else {
415 }
416
417 while (1) {
418 if (s_fault_pending != 0U) {
419 s_fault_pending = 0U;
421 }
422 g_mpu_simple_match += 1U;
425 }
427}
void main(void)
Secure fallback main entry point.
Definition main.c:37
static volatile uint8_t s_fault_pending
Set non-zero by the recovering MemManage handler so the main loop can emit the user-visible "fault ha...
Definition main.c:101
static ra8_err_t internal_mpu_simple_probe(void)
Probe the RO region with a write – expected to fault on silicon.
Definition main.c:257
static void internal_mpu_simple_emit_banner(void)
Emit the banner once after the recovering handler fires.
Definition main.c:388
void MemManage_Handler(void)
Definition main.c:347
static void internal_mpu_simple_setup_or_halt(void)
Bring CGC + SysTick + LEDs + the SCI8 console UART up.
Definition main.c:201
volatile uint32_t g_mpu_simple_fault_count
HIL diagnostic counter – incremented by the recovering MemManage handler every time the deliberate RO...
Definition main.c:135
mpu_simple_region_t
Definition main.c:66
@ k_mpu_simple_mair0_word
Slot 0 = Normal WB RW-allocate.
Definition main.c:68
@ k_mpu_simple_region_size
Smallest legal Armv8-M MPU region.
Definition main.c:67
mpu_simple_frame_t
Stacked-frame layout for an Armv8-M exception entry (no FP).
Definition main.c:84
@ k_mpu_simple_frame_pc_idx
r0..r3, r12, lr, PC, xPSR.
Definition main.c:85
static const ra8_mpu_region_t s_regions[]
One-region RO descriptor covering s_ro_buffer.
Definition main.c:155
static uint8_t s_ro_buffer[k_mpu_simple_region_size]
32-byte aligned scratch buffer the RO region will cover.
Definition main.c:89
thumb_decode_t
Thumb-2 first-halfword decode constants.
Definition main.c:58
@ k_thumb2_prefix_11110
32-bit Thumb-2 first-halfword prefix 0b11110.
Definition main.c:62
@ k_thumb2_prefix_11111
32-bit Thumb-2 first-halfword prefix 0b11111.
Definition main.c:63
@ k_thumb2_prefix_11101
32-bit Thumb-2 first-halfword prefix 0b11101.
Definition main.c:61
@ k_thumb_hi5_shift
Shift to the top 5 bits of the halfword.
Definition main.c:59
@ k_thumb_hi5_mask
Mask for the top 5 bits.
Definition main.c:60
mpu_simple_timing_t
Heartbeat cadence + UART line rate.
Definition main.c:78
@ k_mpu_simple_period_ms
MPU simple period ms.
Definition main.c:79
@ k_mpu_simple_baud
MPU simple baud.
Definition main.c:80
static void internal_mpu_simple_panic_halt(void)
Park the CPU after a fatal UART, clock, LED, or MPU setup failure.
Definition main.c:147
volatile uint32_t g_mpu_simple_match
HIL liveness counter – incremented by main() on every loop iteration after the RO probe + fault-recov...
Definition main.c:121
mpu_simple_attr_t
MAIR slot encoding + probe sentinel.
Definition main.c:72
@ k_mpu_simple_attr_normal_wb
MPU simple attr normal wb.
Definition main.c:73
@ k_mpu_simple_probe_byte
Sentinel byte written by internal_mpu_simple_probe.
Definition main.c:74
static const uint8_t s_mpu_simple_banner[]
Greeting line for the "fault handled" banner.
Definition main.c:375
static void internal_mpu_simple_fault_recover(uint32_t *frame)
Recovering MemManage handler.
Definition main.c:316
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_led_toggle(ra8_board_led_id_t led)
Toggle led's output state.
ra8_err_t ra8_board_led_init(ra8_board_led_id_t led)
Configure led as a digital output, initial level low (off).
ra8_err_t ra8_board_led_on(ra8_board_led_id_t led)
Drive led HIGH (light it).
@ k_ra8_board_led2
LED2, GREEN, P303 (jumper E26).
@ k_ra8_board_led1
LED1, BLUE, P600 (jumper E27).
@ k_ra8_board_led3
LED3, RED, PA07 (jumper E28).
ra8_err_t ra8_board_uart_console_write(const uint8_t *data, size_t len)
Polled blocking write to the J-Link OB VCOM console.
ra8_err_t ra8_board_uart_console_init(uint32_t baud)
Configure SCI8 + PD02/PD03 as the debug-console UART.
Boot entry points shared between a vector table and its startup code.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_get_clock_hz(ra8_clock_id_t id, uint32_t *out_hz)
Query the current frequency of a clock-tree domain.
Definition ra8_cgc.c:132
@ k_ra8_clock_id_cpuclk0
Cortex-M85 CPUCLK0.
Definition ra8_cgc.h:70
ra8_err_t ra8_cgc_init(void)
Configure the clock tree to a safe default.
Definition ra8_cgc.c:727
Error Code Definitions for ra8-firmware.
@ 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
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
NVIC + ICU IELSR allocator.
void ra8_isr_globals_enable(void)
Globally enable maskable interrupts (PRIMASK = 0).
Definition ra8_isr.c:439
Cortex-M85 Memory Protection Unit (MPU) configuration helper.
@ k_ra8_mpu_perm_ro
Read-only at this privilege level.
Definition ra8_mpu.h:43
ra8_err_t ra8_mpu_configure(const ra8_mpu_cfg_t *cfg)
Program every MPU region from a static configuration.
Definition ra8_mpu.c:206
@ k_ra8_mpu_attr_idx_0
MAIR0 byte 0.
Definition ra8_mpu.h:66
@ k_ra8_mpu_share_inner
Inner shareable.
Definition ra8_mpu.h:56
static ra8_power_profile_config_t s_cfg
Cached copy of the caller-supplied configuration.
SysTick-based tick counter, delay and timestamp helpers.
ra8_err_t ra8_time_init(uint32_t cpu_hz)
Initialise SysTick for a 1 kHz tick interrupt.
Definition ra8_time.c:59
void ra8_delay_ms(uint32_t ms)
Busy-wait for at least ms milliseconds.
Definition ra8_time.c:129
Whole-MPU static configuration block.
Definition ra8_mpu.h:150
Static descriptor for one Armv8-M MPU region.
Definition ra8_mpu.h:130