ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ns_main.c
Go to the documentation of this file.
1
27
28#include <stdint.h>
29
30#include "ra8_attributes.h"
31#include "ra8_err.h"
32#include "ra8_nsc.h"
33#include "ra8_wdt_supervisor.h"
34#include "tx_api.h"
35
36/* Linker symbols for BSS and Stack */
37extern uint32_t g_ra8_ls_ns_bss_start;
38extern uint32_t g_ra8_ls_ns_bss_end;
39extern uint32_t g_ra8_ls_ns_stack_top;
40extern uint32_t g_ra8_ls_ns_run_start;
41
42#ifdef RA8_EREADER_NS_XIP
43/* XIP-only: .data lives (writable) in SRAM but its init image is in OSPI. These
44 * mark the OSPI load image (LMA) and the SRAM run bounds (VMA) so the NS reset
45 * handler can copy it in -- the Secure boot no longer copies the whole image. */
46extern uint32_t g_ra8_ls_ns_data_load_start;
47extern uint32_t g_ra8_ls_ns_data_start;
48extern uint32_t g_ra8_ls_ns_data_end;
49#endif
50
52typedef enum : uintptr_t {
53 k_ns_scb_vtor_addr = 0xE000ED08U,
55
61typedef enum : uint32_t {
65
68
71
85
94typedef enum : uint32_t {
98
107typedef enum : uint32_t {
111
129
138typedef enum : uint32_t {
141
143[[gnu::aligned(8)]] static uint8_t s_sup_stack[k_ns_wdt_sup_stack_size];
144
149
160volatile uint32_t g_ns_ui_frames = 0U;
169volatile uint32_t g_ns_sys_ticks = 0U;
170
184extern void PendSV_Handler(void);
185
198extern void _tx_timer_interrupt(void);
199
200/* External state for the thread tick hook. */
201extern volatile uint32_t g_ra8_threadx_systick_ready;
202
219{
220 if (g_ra8_threadx_systick_ready != 0U) {
222 }
223}
224
239RA8_INTERNAL [[noreturn]] static void internal_panic_halt(void)
240{
241 while (1) {
242 __asm__ volatile("wfi");
243 }
244}
245
263{
264 (void)thread_input;
265 (void)ra8_nsc_log_emit("UI", "UI thread started");
266
267 uint32_t frame = 0U;
268 for (;;) {
269 frame++;
270 g_ns_ui_frames = frame; /* HIL liveness probe (read via J-Link). */
271 /* Prove liveness to the watchdog supervisor once per frame. */
273 if ((frame % (uint32_t)k_ns_ui_heartbeat_frames) == 0U) {
274 (void)ra8_nsc_log_emit("UI", "UI loop: frame heartbeat");
275 }
276 tx_thread_sleep((uint32_t)k_ns_ui_frame_ticks); /* ~16 ms; yields to the others. */
277 }
278}
279
297{
298 (void)thread_input;
299
300 (void)ra8_nsc_log_emit("SYS", "System thread started (storage + supervisor)");
301 uint32_t tick = 0U;
302 for (;;) {
303 tick++;
304 g_ns_sys_ticks = tick; /* HIL liveness probe (read via J-Link). */
305 /* Prove liveness to the watchdog supervisor once per poll. */
307 if ((tick % (uint32_t)k_ns_sys_heartbeat_iters) == 0U) {
308 (void)ra8_nsc_log_emit("SYS", "System heartbeat: supervisor loop");
309 }
311 }
312}
313
334{
335 if (ra8_nsc_wdt_start() != k_ra8_ok) {
337 }
338 const ra8_wdt_sup_cfg_t sup_cfg = {
339 .stack = s_sup_stack,
340 .stack_size_bytes = (uint32_t)k_ns_wdt_sup_stack_size,
341 .priority = (uint32_t)k_ns_wdt_sup_priority,
342 .refresh_period_ms = (uint32_t)k_ns_wdt_refresh_ms,
343 };
344 if (ra8_wdt_supervisor_init(&sup_cfg) != k_ra8_ok) {
346 }
347 /* Route refresh through the NSC veneer -- the WDT is Secure-owned, so the
348 * library's default direct ra8_wdt_refresh_deferred would fault in NS. */
351 }
353 (uint32_t)k_ns_wdt_ui_deadline_ms,
356 }
358 (uint32_t)k_ns_wdt_sys_deadline_ms,
361 }
364 }
365}
366
370void tx_application_define(void* first_unused_memory)
371{
372 (void)first_unused_memory;
373
374 /* Arm the WDT + start the check-in supervisor before any worker runs. */
376
377 /* Create the UI thread. A failed create is unrecoverable this early: the
378 * WDT supervisor already registered the "ui"/"sys" deadlines, so a missing
379 * worker would only surface later as a silent watchdog boot-loop -- panic
380 * now instead, like every other NS bring-up failure in this file. */
381 /* (CHAR*)(uintptr_t): the vendored ThreadX API takes a non-const CHAR* for
382 * the thread name; the uintptr_t hop launders the string-literal const
383 * without tripping -Wcast-qual (same pattern as ra8_wdt_supervisor). */
385 (CHAR*)(uintptr_t)"UI Thread",
387 0UL,
390 k_ns_ui_priority, /* Priority */
391 k_ns_ui_priority, /* Preemption threshold */
395 }
396
397 /* Create the System/Storage thread */
399 (CHAR*)(uintptr_t)"System Thread",
401 0UL,
404 k_ns_sys_priority, /* Priority */
405 k_ns_sys_priority, /* Preemption threshold */
409 }
410}
411
429[[noreturn]] void ns_reset_handler(void);
430
431[[noreturn]] void ns_reset_handler(void)
432{
433#ifdef RA8_EREADER_NS_XIP
434 /* XIP: code/rodata execute in place from OSPI, but .data must be writable, so
435 * copy its init image from OSPI (LMA) into SRAM (VMA) before any initialised
436 * global is read. Must run first -- nothing below may touch a .data global. */
437 const uintptr_t data_src = (uintptr_t)&g_ra8_ls_ns_data_load_start;
438 const uintptr_t data_dst = (uintptr_t)&g_ra8_ls_ns_data_start;
439 const uintptr_t data_end = (uintptr_t)&g_ra8_ls_ns_data_end;
440 for (uintptr_t off = 0U; (data_dst + off) < data_end; off += sizeof(uint32_t)) {
441 *(volatile uint32_t*)(data_dst + off) = *(const volatile uint32_t*)(data_src + off);
442 }
443#endif
444
445 /* Zero the NS BSS section */
446 const uintptr_t bss_start = (uintptr_t)&g_ra8_ls_ns_bss_start;
447 const uintptr_t bss_end = (uintptr_t)&g_ra8_ls_ns_bss_end;
448 for (uintptr_t addr = bss_start; addr < bss_end; addr += sizeof(uint32_t)) {
449 *(volatile uint32_t*)addr = 0U;
450 }
451
452 /* Set the NS VTOR so exceptions vector correctly to NS handlers */
453 *(volatile uint32_t*)k_ns_scb_vtor_addr = (uint32_t)(uintptr_t)&g_ra8_ls_ns_run_start;
454
455 /* Call Secure-side substrate initialization via NSC veneer gateway */
456 if (ra8_nsc_periph_init() != k_ra8_ok) {
458 }
459
460 /* Announce the Non-Secure world is live before handing off to ThreadX.
461 * Logs flow NS -> ra8_nsc_log_emit veneer -> Secure ra8_log_info -> ITM
462 * (visible on the J-Link SWO console). */
463 (void)ra8_nsc_log_emit("BOOT", "ra8d2-ereader: Non-Secure world online");
464
465 /* Enter ThreadX RTOS kernel (never returns) */
466 tx_kernel_enter();
467
469}
470
471/* =============================================================================
472 * Non-Secure Vector Table
473 * =============================================================================
474 */
475typedef void (*ns_exc_handler_t)(void);
476
491RA8_INTERNAL [[noreturn]] static void internal_nmi_halt(void)
492{
493 while (1) {
494 __asm__ volatile("wfi");
495 }
496}
497
498[[gnu::section(".ns_vectors"), gnu::used]] const ns_exc_handler_t g_ra8_ns_vector_table[16] = {
499 (ns_exc_handler_t)&g_ra8_ls_ns_stack_top, /* 0 Initial MSP_NS */
500 ns_reset_handler, /* 1 Reset */
501 internal_nmi_halt, /* 2 NMI */
502 internal_nmi_halt, /* 3 HardFault */
503 internal_nmi_halt, /* 4 MemManage */
504 internal_nmi_halt, /* 5 BusFault */
505 internal_nmi_halt, /* 6 UsageFault */
506 internal_nmi_halt, /* 7 SecureFault */
507 0, /* 8 Reserved */
508 0, /* 9 Reserved */
509 0, /* 10 Reserved */
510 internal_nmi_halt, /* 11 SVCall */
511 internal_nmi_halt, /* 12 DebugMonitor */
512 0, /* 13 Reserved */
513 PendSV_Handler, /* 14 PendSV */
514 internal_systick_handler, /* 15 SysTick */
515};
static uint8_t s_sys_wdt_handle
Supervisor check-in handle for the system thread.
Definition ns_main.c:148
@ k_ns_ui_heartbeat_frames
UI heartbeat every ~60 frames (~1 s).
Definition ns_main.c:82
@ k_ns_sys_heartbeat_iters
System heartbeat every ~10 loops (~1 s).
Definition ns_main.c:83
ns_thread_sleep_t
Per-thread loop sleep period, in ThreadX ticks.
Definition ns_main.c:94
@ k_ns_sys_poll_ticks
System loop sleep (~100 ms cadence).
Definition ns_main.c:96
@ k_ns_ui_frame_ticks
UI loop sleep (~16 ms, ~60 FPS).
Definition ns_main.c:95
static uint8_t s_ui_wdt_handle
Supervisor check-in handle for the UI thread.
Definition ns_main.c:146
void PendSV_Handler(void)
Perform the ThreadX Non-Secure context switch requested by PendSV.
static uint8_t s_sys_thread_stack[k_ns_sys_thread_stack_size]
Definition ns_main.c:70
ns_wdt_prio_t
ThreadX priority for the watchdog supervisor thread.
Definition ns_main.c:138
@ k_ns_wdt_sup_priority
Supervisor thread priority.
Definition ns_main.c:139
static void internal_nmi_halt(void)
Default Non-Secure fault/NMI handler: park the CPU in a wfi halt.
Definition ns_main.c:491
static TX_THREAD s_sys_thread
Definition ns_main.c:67
void _tx_timer_interrupt(void)
Advance the ThreadX kernel timer by one hardware tick.
static void internal_panic_halt(void)
Park the CPU in an idle loop if a fatal startup error occurs.
Definition ns_main.c:239
static void internal_wdt_setup(void)
Arm the watchdog and start the ThreadX check-in supervisor.
Definition ns_main.c:333
@ k_ns_sys_thread_stack_size
Stack size for System thread.
Definition ns_main.c:63
volatile uint32_t g_ns_sys_ticks
HIL liveness probe: system-thread iteration count.
Definition ns_main.c:169
static void internal_sys_thread_entry(ULONG thread_input)
System supervisor and storage background thread.
Definition ns_main.c:296
static void internal_systick_handler(void)
SysTick exception handler for the Non-Secure ThreadX OS.
Definition ns_main.c:218
void ns_reset_handler(void)
Non-Secure Reset handler: entered via Secure-to-NS transition.
Definition ns_main.c:431
ns_wdt_param_t
Watchdog-supervisor sizing and timing parameters.
Definition ns_main.c:123
@ k_ns_wdt_ui_deadline_ms
UI worker check-in deadline (ms).
Definition ns_main.c:125
@ k_ns_wdt_refresh_ms
Supervisor refresh / poll cadence (ms).
Definition ns_main.c:127
@ k_ns_wdt_sys_deadline_ms
System worker check-in deadline (ms).
Definition ns_main.c:126
@ k_ns_wdt_sup_stack_size
Supervisor thread stack size (bytes).
Definition ns_main.c:124
ns_thread_prio_t
ThreadX priority + preemption threshold for each Non-Secure thread.
Definition ns_main.c:107
@ k_ns_ui_priority
UI thread priority + preemption threshold.
Definition ns_main.c:108
@ k_ns_sys_priority
System thread priority + preemption threshold.
Definition ns_main.c:109
volatile uint32_t g_ns_ui_frames
HIL liveness probe: UI-thread iteration count.
Definition ns_main.c:160
void tx_application_define(void *first_unused_memory)
Setup ThreadX threads and resources.
Definition ns_main.c:370
static void internal_ui_thread_entry(ULONG thread_input)
UI thread entry: runs the e-reader UI frame loop.
Definition ns_main.c:262
const uint32_t g_ra8_ns_vector_table[8]
NS-world ARMv8-M vector table.
Definition ns_main.c:455
uint32_t g_ra8_ls_ns_stack_top
uint32_t g_ra8_ls_ns_bss_start
NS world reset handler – entry point of the BLXNS branch.
void ns_reset_handler(void)
Definition ns_main.c:384
uint32_t g_ra8_ls_ns_bss_end
ns_scb_addr_t
NS-state VTOR (0xE000ED08 is the current-domain alias in NS).
Definition ns_main.c:158
@ k_ns_scb_vtor_addr
Ns scb vtor address.
Definition ns_main.c:159
void(* ns_exc_handler_t)(void)
Function-pointer type for entries in the NS vector table.
Definition ns_main.c:337
uint32_t g_ra8_ls_ns_run_start
Linker symbol: NS vector table base.
ns_log_cadence_t
Heartbeat-log cadence per thread (iterations between log lines).
Definition ns_main.c:58
static TX_THREAD s_ui_thread
Definition ns_main.c:47
ns_thread_stack_t
Stack sizes for Non-Secure ThreadX threads.
Definition ns_main.c:42
@ k_ns_ui_thread_stack_size
Stack size for UI thread.
Definition ns_main.c:43
static uint8_t s_ui_thread_stack[k_ns_ui_thread_stack_size]
Definition ns_main.c:50
static uint8_t s_sup_stack[k_wdt_sup_demo_stack_bytes]
Definition main.c:50
void PendSV_Handler(void)
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
Non-Secure Callable veneers – the only NS->S gateway.
ra8_err_t ra8_nsc_wdt_start(void)
NSC veneer: arm the Secure WDT with the e-reader configuration.
Definition ra8_nsc_wdt.c:82
ra8_err_t ra8_nsc_log_emit(const char *tag, const char *message)
NSC veneer: emit a log line via the secure ITM channel.
Definition ra8_nsc_log.c:94
void ra8_nsc_wdt_refresh(void)
NSC veneer: refresh the Secure WDT down-counter.
ra8_err_t ra8_nsc_periph_init(void)
NSC veneer: bring up the secure-side peripheral substrate.
volatile uint32_t g_ra8_threadx_systick_ready
0 until _tx_initialize_low_level has armed ThreadX's SysTick + timer state; 1 afterwards.
#define TX_SUCCESS
#define tx_thread_create
#define tx_thread_sleep
#define TX_NO_TIME_SLICE
char CHAR
ThreadX-compatible CHAR (host stub).
#define TX_AUTO_START
unsigned long ULONG
ThreadX-compatible unsigned long (host stub).
ThreadX-aware watchdog supervisor (per-thread check-in registry).
ra8_err_t ra8_wdt_supervisor_register_thread(const char *name, uint32_t deadline_ms, uint8_t *out_handle)
Register a worker thread with the supervisor.
ra8_err_t ra8_wdt_supervisor_checkin(uint8_t handle)
Record a thread check-in, resetting its deadline window.
ra8_err_t ra8_wdt_supervisor_init(const ra8_wdt_sup_cfg_t *cfg)
Initialise the supervisor registry and runtime hooks.
@ k_ra8_wdt_sup_handle_invalid
Invalid / unregistered handle.
ra8_err_t ra8_wdt_supervisor_set_refresh_hook(ra8_wdt_sup_refresh_fn_t refresh)
Override the WDT-refresh hook (test injection point).
ra8_err_t ra8_wdt_supervisor_start(void)
Spawn the supervisor thread.
Opaque thread stand-in for the host build.
One-shot supervisor configuration block.