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

Self-contained Non-Secure image at 0x02080000 for the IPC ping-pong demo. More...

#include <stdint.h>
#include "ra8_attributes.h"
Include dependency graph for ns_main.c:

Go to the source code of this file.

Enumerations

enum  ns_ipc_const_t : uintptr_t {
  k_ns_ipc_base = 0x50020000UL ,
  k_ns_ipc_ch0_addr = 0x500200C0UL ,
  k_ns_ipc_ch2_addr = 0x50020100UL
}
 Register layout for the IPC channels CPU0 owns in NS state. More...
enum  ns_ipc_off_t : uint8_t {
  k_ns_ipc_off_sta = 0x00U ,
  k_ns_ipc_off_set = 0x04U ,
  k_ns_ipc_off_txd = 0x08U ,
  k_ns_ipc_off_rxd = 0x0CU ,
  k_ns_ipc_off_clr = 0x10U
}
 In-channel offsets for STA/ISET/TXD/RXD/CLR. More...
enum  ns_ipc_sta_mask_t : uint32_t { k_ns_ipc_sta_rdy = 0x00010000UL }
 STA register bits we care about. More...
enum  ns_pingpong_step_t : uint32_t {
  k_ns_step_bss_zeroed = 1U ,
  k_ns_step_channels_up = 2U ,
  k_ns_step_tx_start = 3U ,
  k_ns_step_tx_done = 5U ,
  k_ns_step_rx_timeout = 6U ,
  k_ns_step_rx_word = 7U
}
 Progress markers written to g_ns_pingpong_step. More...
enum  ns_pingpong_marker_t : uint32_t { k_ns_entry_marker = 0xCAFEBABEUL }
 Sentinel written to g_ns_pingpong_entry_marker. More...
enum  ns_ipc_clr_mask_t : uint32_t { k_ns_ipc_clr_all = 0x030100FFUL }
 CLR register bits we use for init / status clear. More...
enum  ns_pingpong_magic_t : uint32_t {
  k_ns_magic_ping = 0x1234U ,
  k_ns_magic_pong = 0x4321U
}
 Ping-pong handshake words exchanged between CPU0 and CPU1. More...
enum  ns_pingpong_poll_t : uint32_t { k_ns_recv_poll_max = 1000000UL }
 Receive poll budget per ping-pong iteration. More...

Functions

static void internal_ns_write32 (uintptr_t addr, uint32_t value)
 32-bit MMIO write helper.
static uint32_t internal_ns_read32 (uintptr_t addr)
 32-bit MMIO read helper.
static void internal_ns_ipc_channel_reset (uintptr_t ch_base)
 Reset one IPC channel's FIFO and clear all sticky status bits.
static void internal_ns_ipc_send (uintptr_t ch_base, uint32_t msg)
 Push one 32-bit word onto a channel's transmit FIFO.
static uint32_t internal_ns_ipc_recv (uintptr_t ch_base, uint32_t *out_word)
 Bounded RDY poll + single drain of a channel's receive FIFO.
void ns_reset_handler (void)

Variables

volatile uint32_t g_ns_pingpong_match = 0U
 NS-side HIL liveness counter.
volatile uint32_t g_ns_pingpong_mismatch = 0U
 NS-side HIL failure counter.
volatile uint32_t g_ns_pingpong_step = 0U
 NS reset-handler progress tracker.
volatile uint32_t g_ns_pingpong_last_rxd = 0U
 Most recent word read off the receive channel.
volatile uint32_t g_ns_pingpong_entry_marker = 0U
 First word stamped by ns_reset_handler – proves NS state actually entered the image (vs the S fallback path).
uint32_t g_ra8_ls_ns_bss_start
 NS world reset handler – entry point of the BLXNS branch.
uint32_t g_ra8_ls_ns_bss_end
uint32_t g_ra8_ls_ns_stack_top
const uint32_t g_ra8_ns_vector_table [8]
 NS-world ARMv8-M vector table.

Detailed Description

Self-contained Non-Secure image at 0x02080000 for the IPC ping-pong demo.

Tag
[Ring 1 / app] {World: NS}

After the S-side trustzone_init programmes the SAU and writes IPCSAR=0x00050000 it BLXNS-es to ns_reset_handler here. Once CPU0 is in NS state the IPCSAR-attributed channels 0 (CPU1->CPU0) and 2 (CPU0->CPU1) become reachable. The S side has already released CPU1 via ra8_cpu1_release before the BLXNS, so CPU1 is fetching its own image and is the IPC peer for the ping-pong loop below.

The NS image is intentionally self-contained: it cannot call any function whose code resides in S MRAM without an NSC veneer, so the IPC accessors are open-coded against the register window. Counters live in NS SRAM and are read externally via SWD (the J-Link debug controller sees both worlds).

Memory layout

Symbol Section Address
g_ra8_ns_vector_table .ns_vectors 0x02080000
ns_reset_handler .ns_text 0x02080000+
g_ns_pingpong_* counters .ns_bss 0x22100000+
Since
0.1.0

Definition in file ns_main.c.

Enumeration Type Documentation

◆ ns_ipc_clr_mask_t

enum ns_ipc_clr_mask_t : uint32_t

CLR register bits we use for init / status clear.

  • Bit 16 RST resets the FIFO + clears RDY/FULL.
  • Bits 7..0 (CLR7..CLR0) drop the eight IRQ status bits.
  • Bits 24/25 (RCLR/FCLR) drop the RERR/FERR FIFO error sticky bits.
  • HUM Ch 3.2.14 "IPC0CLR0" p 216-217.
Enumerator
k_ns_ipc_clr_all 

RST | RCLR | FCLR | CLR7..CLR0.

Definition at line 129 of file ns_main.c.

◆ ns_ipc_const_t

enum ns_ipc_const_t : uintptr_t

Register layout for the IPC channels CPU0 owns in NS state.

  • k_ns_ipc_base is the IPC peripheral window in the secure alias. Bit 28 IDAU rule says this is S by default; the SAU NS_PERIPH region pulled in by ra8_tz_secure_boot_sau_init (now extended to 0x40000000-0x5FFFFFE0) lets NS code reach it.
  • Channel 0 is at +0x0C0 (CPU1->CPU0 receive path).
  • Channel 2 is at +0x100 (CPU0->CPU1 send path).
  • Each channel is 5 x 32-bit registers laid out STA / ISET / TXD / RXD / CLR, then padding to the next channel at +0x20.
  • HUM Ch 3.2.10..3.2.14 p 214-216.
Enumerator
k_ns_ipc_base 

IPC peripheral base (NS alias).

k_ns_ipc_ch0_addr 

CPU0 RX from CPU1 (NS alias).

k_ns_ipc_ch2_addr 

CPU0 TX to CPU1 (NS alias).

Definition at line 61 of file ns_main.c.

◆ ns_ipc_off_t

enum ns_ipc_off_t : uint8_t

In-channel offsets for STA/ISET/TXD/RXD/CLR.

Enumerator
k_ns_ipc_off_sta 

Status register.

k_ns_ipc_off_set 

IRQ set (W).

k_ns_ipc_off_txd 

FIFO transmit (W).

k_ns_ipc_off_rxd 

FIFO receive (R).

k_ns_ipc_off_clr 

Status / FIFO clear.

Definition at line 71 of file ns_main.c.

◆ ns_ipc_sta_mask_t

enum ns_ipc_sta_mask_t : uint32_t

STA register bits we care about.

HUM Ch 3.2.10 "IPC0STA0" p 214 – bit 16 RDY = FIFO non-empty.

Enumerator
k_ns_ipc_sta_rdy 

RDY: receive FIFO non-empty.

Definition at line 85 of file ns_main.c.

◆ ns_pingpong_magic_t

enum ns_pingpong_magic_t : uint32_t

Ping-pong handshake words exchanged between CPU0 and CPU1.

Enumerator
k_ns_magic_ping 

CPU0 -> CPU1 ping word.

k_ns_magic_pong 

CPU1 -> CPU0 pong word.

Definition at line 137 of file ns_main.c.

◆ ns_pingpong_marker_t

enum ns_pingpong_marker_t : uint32_t

Sentinel written to g_ns_pingpong_entry_marker.

Stamped AFTER the .bss zero so the bench can tell "BLXNS reached NS" apart from "the marker happened to land back at 0".

Invariant
Not a plausible uninitialised-SRAM pattern.
See also
ns_pingpong_step_t
Enumerator
k_ns_entry_marker 

NS entry was reached.

Definition at line 115 of file ns_main.c.

◆ ns_pingpong_poll_t

enum ns_pingpong_poll_t : uint32_t

Receive poll budget per ping-pong iteration.

Enumerator
k_ns_recv_poll_max 

Max iterations of the RDY spin.

Definition at line 146 of file ns_main.c.

◆ ns_pingpong_step_t

enum ns_pingpong_step_t : uint32_t

Progress markers written to g_ns_pingpong_step.

The bench reads this word over J-Link to see how far the NS image got. Values ascend with execution order, so a dump alone says where it stopped.

Invariant
Values ascend in execution order.
See also
ns_pingpong_marker_t
Enumerator
k_ns_step_bss_zeroed 

.bss zeroed, entry marker stamped.

k_ns_step_channels_up 

Both IPC channels cold-initialised.

k_ns_step_tx_start 

About to write the ping.

k_ns_step_tx_done 

Survived the TX write.

k_ns_step_rx_timeout 

TX succeeded, RX timed out.

k_ns_step_rx_word 

RX returned a word.

Definition at line 98 of file ns_main.c.

Function Documentation

◆ internal_ns_ipc_channel_reset()

void internal_ns_ipc_channel_reset ( uintptr_t ch_base)
static

Reset one IPC channel's FIFO and clear all sticky status bits.

Parameters
[in]ch_baseBase address of the channel (e.g. k_ns_ipc_ch0_addr).
Precondition
ch_base is one of the four channel windows documented in HUM Ch 3.2.10..3.2.14 p 214-216.
IPCSAR has been programmed so the channel is NS-accessible.
Postcondition
Channel STA reports RDY=0, FULL=0, RERR=0, FERR=0, IRQ7..0=0.
FIFO contents discarded (any in-flight peer message lost; on a cold ping-pong bring-up the peer has not sent anything yet).
Note
Not thread-safe – caller owns this channel.
Since
0.1.0

Definition at line 281 of file ns_main.c.

References internal_ns_write32(), k_ns_ipc_clr_all, and k_ns_ipc_off_clr.

Referenced by ns_reset_handler().

◆ internal_ns_ipc_recv()

uint32_t internal_ns_ipc_recv ( uintptr_t ch_base,
uint32_t * out_word )
static

Bounded RDY poll + single drain of a channel's receive FIFO.

Parameters
[in]ch_baseChannel base address.
[out]out_wordReceives the dequeued word on success.
Returns
0 on success, 1 on timeout.
Precondition
out_word is non-NULL.
Loop is bounded by k_ns_recv_poll_max (NASA P10 Rule 2).
Postcondition
On success *out_word holds the peer's word and STA.RDY has been cleared by the RXD read.
On timeout *out_word is unchanged.
Note
A null output pointer is rejected with the same nonzero result as a timeout.
Since
0.1.0

Definition at line 331 of file ns_main.c.

References internal_ns_read32(), k_ns_ipc_off_rxd, k_ns_ipc_off_sta, k_ns_ipc_sta_rdy, k_ns_recv_poll_max, and RA8_INTERNAL.

Referenced by ns_reset_handler().

◆ internal_ns_ipc_send()

void internal_ns_ipc_send ( uintptr_t ch_base,
uint32_t msg )
static

Push one 32-bit word onto a channel's transmit FIFO.

Parameters
[in]ch_baseChannel base address.
[in]msgWord to push.
Precondition
ch_base is owned by the caller (no concurrent sender).
The peer has either drained the FIFO or is keeping up; we do not check FULL because the ping-pong handshake is depth-1.
Postcondition
One word added to the channel's transmit FIFO; the peer's STA.RDY rises one cycle later.
Note
This depth-one protocol deliberately does not poll FIFO fullness.
Since
0.1.0

Definition at line 304 of file ns_main.c.

References internal_ns_write32(), k_ns_ipc_off_txd, and RA8_INTERNAL.

Referenced by ns_reset_handler().

◆ internal_ns_read32()

uint32_t internal_ns_read32 ( uintptr_t addr)
inlinestatic

32-bit MMIO read helper.

Parameters
[in]addrPhysical address.
Returns
Value at addr.
Precondition
addr is 4-byte aligned and reachable from NS.
Postcondition
Caller can act on the returned value (caller-side handles the volatile semantics).
Note
The helper performs one volatile load and has no retry policy.
Since
0.1.0

Definition at line 259 of file ns_main.c.

References RA8_INTERNAL.

Referenced by internal_ns_ipc_recv().

◆ internal_ns_write32()

void internal_ns_write32 ( uintptr_t addr,
uint32_t value )
inlinestatic

32-bit MMIO write helper.

Parameters
[in]addrPhysical address.
[in]valueValue to write.
Precondition
addr lies in a region the current SAU attribution permits.
addr is 4-byte aligned.
Postcondition
One volatile bus write of value is issued.
Note
The volatile access prevents compiler elision; callers provide any hardware ordering required around the register transaction.
Since
0.1.0

Definition at line 243 of file ns_main.c.

References RA8_INTERNAL.

Referenced by internal_ns_ipc_channel_reset(), and internal_ns_ipc_send().

◆ ns_reset_handler()

Variable Documentation

◆ g_ns_pingpong_entry_marker

volatile uint32_t g_ns_pingpong_entry_marker = 0U

First word stamped by ns_reset_handler – proves NS state actually entered the image (vs the S fallback path).

If BLXNS in ra8_tz_secure_boot_jump_ns succeeded in transferring control to ns_reset_handler, this counter is stamped to 0xCAFEBABE before any other NS work happens. If it stays at 0 across a bench probe window, BLXNS failed to enter NS state and the boot continued in S.

Note
Read externally by J-Link only.
Since
0.1.0

Definition at line 225 of file ns_main.c.

Referenced by ns_reset_handler().

◆ g_ns_pingpong_last_rxd

volatile uint32_t g_ns_pingpong_last_rxd = 0U

Most recent word read off the receive channel.

Latched on every successful drain regardless of magic value, so the bench can confirm "CPU1 is talking back" even if the magic comparison disagrees with the expected pong word.

Since
0.1.0

Definition at line 208 of file ns_main.c.

Referenced by ns_reset_handler().

◆ g_ns_pingpong_match

volatile uint32_t g_ns_pingpong_match = 0U

NS-side HIL liveness counter.

Increment is one full CPU0->CPU1->CPU0 round-trip where CPU0 sent k_ns_magic_ping on channel 2 and CPU1 returned k_ns_magic_pong on channel 0. Read externally over SWD; the memprobe gate asserts strictly monotonic growth.

Note
Read by J-Link only. The S-side debugger sees NS SRAM through the DAP regardless of attribution.
Since
0.1.0

Definition at line 169 of file ns_main.c.

Referenced by ns_reset_handler().

◆ g_ns_pingpong_mismatch

volatile uint32_t g_ns_pingpong_mismatch = 0U

NS-side HIL failure counter.

Bumped whenever a CPU0 iteration could not complete – RX timed out after k_ns_recv_poll_max polls, or the returned word was not the expected pong magic. Stays at 0 on a healthy bench.

Since
0.1.0

Definition at line 181 of file ns_main.c.

Referenced by ns_reset_handler().

◆ g_ns_pingpong_step

volatile uint32_t g_ns_pingpong_step = 0U

NS reset-handler progress tracker.

  • 0 = pre-NS / never reached
  • 1 = ns_reset_handler entry
  • 2 = channels reset
  • 3 = first send attempted
  • 4 = first round-trip completed (also bumps g_ns_pingpong_match)
Since
0.1.0

Definition at line 196 of file ns_main.c.

Referenced by ns_reset_handler().

◆ g_ra8_ls_ns_bss_end

uint32_t g_ra8_ls_ns_bss_end
extern

◆ g_ra8_ls_ns_bss_start

uint32_t g_ra8_ls_ns_bss_start
extern

NS world reset handler – entry point of the BLXNS branch.

Initialises the two channels CPU0 owns (channel 0 for receive, channel 2 for send), then loops ping->pong->bump-counter. The S-side already released CPU1 via ra8_cpu1_release in the trustzone_init path, so CPU1 is online by the time this handler runs.

MSP_NS has been set by the BLXNS prologue in ra8_tz_secure_boot_jump_ns from g_ra8_ns_vector_table[0], so we do not touch the stack pointer here.

BSS is implicitly zero (NS_BSS lives in MRAM at first power-on and each warm reset re-flashes the image), so we do not zero it.

Returns
Never returns.
Precondition
BLXNS has placed the CPU in NS state.
MSP_NS points at the top of the NS stack.
Postcondition
Round-trip loop running; g_ns_pingpong_match advances.
Since
0.1.0

Referenced by ns_reset_handler(), and ns_reset_handler().

◆ g_ra8_ls_ns_stack_top

uint32_t g_ra8_ls_ns_stack_top
extern

◆ g_ra8_ns_vector_table

const uint32_t g_ra8_ns_vector_table[8]
Initial value:
= {
(uint32_t)(uintptr_t)&g_ra8_ls_ns_stack_top,
(uint32_t)(uintptr_t)&ns_reset_handler,
0U,
0U,
0U,
0U,
0U,
0U,
}
uint32_t g_ra8_ls_ns_stack_top
void ns_reset_handler(void)
Definition ns_main.c:384

NS-world ARMv8-M vector table.

Non-Secure vector table; run-time VMA NS_SRAM_RUN (0x32100000).

Slot 0 = initial MSP_NS, slot 1 = reset entry (Thumb bit set by the linker on function symbols), slots 2..7 reserved.

Note
Linker places this at 0x02080000 via the .ns_vectors section.
Since
0.1.0

Slot 0 = initial MSP_NS, slot 1 = ns_reset_handler. Slots 14 (PendSV) and 15 (SysTick) drive the NS-resident ThreadX kernel (#96); fault slots halt. 8-byte aligned per ARMv8-M B3.10 (.ns_vectors aligns to 8).

Since
0.1.0

Slot 0 = initial MSP_NS, slot 1 = ns_reset_handler. Every fault slot halts in ns_nmi_halt. MUST stay exactly 16 entries (64 bytes): the .ns_rot_header the Secure verifier reads is placed immediately after it (see ns_image.ld + k_ra8_tz_ns_rot_header_offset). 8-byte aligned per ARMv8-M B3.10 (.ns_vectors aligns to 8).

Invariant
Exactly 16 entries so the RoT header lands at ns_base + 0x40.
Since
0.1.0

Definition at line 455 of file ns_main.c.