|
ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
|
FSP-style TrustZone secure-boot implementation for RA8D2. More...
#include "ra8_tz_secure_boot.h"#include <stdint.h>#include "ra8_attributes.h"#include "ra8_check.h"#include "ra8_err.h"#include "ra8_log.h"Go to the source code of this file.
Functions | |
| void | ra8_tz_secure_boot_host_reset (void) |
| Reset the host-side state for unit-test fixtures. | |
| uint32_t | ra8_tz_secure_boot_host_blxns_target (void) |
| Read the captured BLXNS target (host / test). | |
| static void | internal_write32 (uintptr_t addr, uint32_t value) |
| Write a 32-bit MMIO register (or capture on host). | |
| static uint32_t | internal_read32 (uintptr_t addr) |
| Read a 32-bit MMIO register (or canned host value). | |
| static void | internal_write16 (uintptr_t addr, uint16_t value) |
| Write a 16-bit MMIO register (or capture on host). | |
| static void | internal_dsb (void) |
| Emit a Data Synchronisation Barrier (no-op on host). | |
| static void | internal_isb (void) |
| Emit an Instruction Synchronisation Barrier (no-op on host). | |
| static void | internal_sau_set_region (uint8_t region, uint32_t base, uint32_t limit, bool is_nsc) |
| Programme one SAU region via RNR/RBAR/RLAR. | |
| ra8_err_t | ra8_tz_secure_boot_sau_init (void) |
| Programme the SAU regions documented in ra8_tz_sau_region_t. | |
| ra8_err_t | ra8_tz_secure_boot_security_init (uint32_t ipcsar_value, uint32_t ipcpar_value) |
| Unlock PRCR_S.PRC4 and write IPCSAR + IPCPAR. | |
| uint32_t | ra8_tz_ns_signed_body_len (const uint32_t *ns_vector_table) |
| Read the NS image's self-describing signed-body length. | |
| static ra8_err_t | internal_ns_verify_or_deny (const uint32_t *ns_vector_table) |
| Authenticate the Non-Secure image before BLXNS (default-deny gate). | |
| ra8_err_t | ra8_tz_secure_boot_jump_ns (const uint32_t *ns_vector_table) |
| Switch to NS state and jump to the NS image's reset vector. | |
| ra8_err_t | ra8_tz_secure_boot_run (uint32_t ipcsar_value, uint32_t ipcpar_value, const uint32_t *ns_vector_table) |
| Run the full secure-boot sequence and (on target) BLXNS. | |
| ra8_tz_secure_boot_step_t | ra8_tz_secure_boot_get_step (void) |
| Read the boot progress counter (debug / test). | |
Variables | |
| static const char * | s_tag = "TZBOOT" |
| Logger tag for the secure-boot module. | |
| static volatile ra8_tz_secure_boot_step_t | s_step = k_ra8_tz_secure_boot_step_idle |
| Progress counter exposed via ra8_tz_secure_boot_get_step. | |
FSP-style TrustZone secure-boot implementation for RA8D2.
See ra8_tz_secure_boot.h for the full contract. This file owns the actual MMIO writes. The implementation is split into three phases (SAU init, security init, BLXNS) so unit tests can drive each phase against the host-side fake mmap.
The host-build path uses RA8_OFF_TARGET to swap the SAU / CPSCU MMIO writes for in-memory captures, lets the tests assert on the documented PRCR-unlock / IPCSAR-write sequence, and replaces the BLXNS instruction with a captured-target-then-return path.
Definition in file ra8_tz_secure_boot.c.
| enum ra8_tz_secure_boot_addr_t : uintptr_t |
Memory-mapped register addresses used by the secure-boot.
SAU registers live in the System Control Space at 0xE000EDD0 (ARMv8-M architectural address). The Cortex-M85 Secure VTOR_NS is at 0xE000ED08 (the regular VTOR; writes to it from Secure state set VTOR_NS when SAU is enabled per ARMv8-M ARM section B3.2.4). CPSCU.IPCSAR / IPCPAR follow the layout in HUM Ch 3.2.1 / 3.2.2. PRCR_S lives in the SYSC block at base 0x4001E000 (HUM Ch 13.2.1).
Definition at line 77 of file ra8_tz_secure_boot.c.
| enum ra8_tz_secure_boot_partition_t : uint32_t |
Canonical SAU region base / limit addresses (HUM Ch 4).
Region 3 (NSC alias) deliberately targets the unused 0x10000000 IDAU alias rather than the actual .gnu.sgstubs placement. See project_sau_sgstubs_brick in project memory for the bench fault that drove that choice. RLAR limits are the upper bound minus the ARMv8-M 32-byte region quantum.
Definition at line 133 of file ra8_tz_secure_boot.c.
| enum ra8_tz_secure_boot_prcr_t : uint16_t |
PRCR_S unlock key + per-group enable bits (HUM Ch 13.2.1).
PRCR_S is a 16-bit register. The upper byte must equal the write key 0xA5 on every write or the entire transaction is dropped. Bit 4 (PRC4) is the gate for CPSCU security-attribution registers.
| Enumerator | |
|---|---|
| k_ra8_tz_prcr_s_key | Unlock key (top byte). |
| k_ra8_tz_prcr_s_prc4_open | PRC4 gate open (bit 4). |
| k_ra8_tz_prcr_s_open | Key | PRC4 (unlock value). |
| k_ra8_tz_prcr_s_close | Key with PRC4 = 0 (lock). |
Definition at line 115 of file ra8_tz_secure_boot.c.
| enum ra8_tz_secure_boot_sau_bit_t : uint32_t |
Bit positions used to enable / configure each SAU region.
Mirrors the ARMv8-M ARM register-field encoding (D.4.5 SAU_CTRL, D.4.7 SAU_RLAR). Names are kept identical to the FSP equivalents so the bench-debug trail is easy to follow.
Definition at line 98 of file ra8_tz_secure_boot.c.
|
inlinestatic |
Emit a Data Synchronisation Barrier (no-op on host).
Wraps the dsb 0xF inline-asm so the file's hot path stays readable. Host build compiles to a true no-op.
Definition at line 369 of file ra8_tz_secure_boot.c.
References RA8_INTERNAL.
Referenced by ra8_trustzone_init(), ra8_tz_secure_boot_sau_init(), and ra8_tz_secure_boot_security_init().
|
inlinestatic |
Emit an Instruction Synchronisation Barrier (no-op on host).
Wraps the isb 0xF inline-asm so the file's hot path stays readable. Host build compiles to a true no-op.
Definition at line 389 of file ra8_tz_secure_boot.c.
References RA8_INTERNAL.
Referenced by ra8_trustzone_init(), and ra8_tz_secure_boot_sau_init().
|
static |
Authenticate the Non-Secure image before BLXNS (default-deny gate).
Root-of-trust gate factored out of ra8_tz_secure_boot_jump_ns so the caller stays within the function-length budget. On a target build with RA8_ENABLE_ROOT_OF_TRUST enabled it reads the NS image's self-describing signed-body length via ra8_tz_ns_signed_body_len (an ra8_ns_rot_header_t the NS linker emits at k_ra8_tz_ns_rot_header_offset), locates the trailer that the signing tool appended immediately after that body via ra8_rot_trailer_after, then re-computes SHA-256 and verifies the NS image's ECDSA-P256 signature against the provisioned root public key via ra8_rot_verify_image. This mirrors the copy-to-run boundary exactly (the trailer sits at ns_vector_table + body_len). Any failure – a missing / bad header, or a failed verify – returns a non-k_ra8_ok error and the caller must NOT BLXNS.
With the flag OFF (default) – or under RA8_OFF_TARGET, where the NS image and trailer do not exist at a real address on the unit-test host – the gate is absent and this returns k_ra8_ok so the jump proceeds unverified, exactly as before. The gate's decision logic is covered directly in tests/security/src/test_ra8_root_of_trust.c and the header read in tests/security/src/test_tz_secure_boot.c.
| [in] | ns_vector_table | Base of the NS image (its vector table); non-NULL. |
| k_ra8_ok | Image authentic, or verification is disabled. |
| k_ra8_err_null_ptr | ns_vector_table is NULL. |
| k_ra8_err_validation_failed | NS RoT header missing / wrong magic. |
| k_ra8_err_invalid_size | Header body length out of range. |
| k_ra8_err_* | Root-of-trust gate denied the NS image. |
Definition at line 589 of file ra8_tz_secure_boot.c.
References k_ra8_err_invalid_size, k_ra8_err_validation_failed, k_ra8_ok, RA8_CHECK_NULL_PTR, RA8_INTERNAL, ra8_log_error, ra8_rot_trailer_after(), ra8_rot_verify_image(), ra8_tz_ns_signed_body_len(), and s_tag.
Referenced by ra8_tz_secure_boot_jump_ns().
|
static |
Read a 32-bit MMIO register (or canned host value).
On target the function dereferences the MMIO address. On host (RA8_OFF_TARGET) it returns the canned values tests expect for SAU_TYPE (= 8 regions) and IPCSAR.
| [in] | addr | Target address. |
| 8U | When addr == k_ra8_tz_sau_type_addr on host. |
| s_host.ipcsar_value | When addr == k_ra8_tz_ipcsar_addr on host. |
| 0U | For any other addr on host. |
Definition at line 304 of file ra8_tz_secure_boot.c.
References k_ra8_tz_ipcsar_addr, k_ra8_tz_sau_type_addr, and RA8_INTERNAL.
Referenced by ra8_trustzone_init(), and ra8_tz_secure_boot_sau_init().
|
static |
Programme one SAU region via RNR/RBAR/RLAR.
Selects region via SAU_RNR, writes the base address into SAU_RBAR, and writes limit | ENABLE [| NSC] into SAU_RLAR. Captures the values into s_host on host so the layout-sanity unit test can inspect them.
| [in] | region | Region index (0..SAU_TYPE.SREGION - 1). |
| [in] | base | Base address (32-byte aligned). |
| [in] | limit | Upper-bound minus 32 (32-byte aligned). |
| [in] | is_nsc | true to mark the region as Non-Secure Callable. |
Definition at line 422 of file ra8_tz_secure_boot.c.
References internal_write32(), k_ra8_tz_sau_rbar_addr, k_ra8_tz_sau_region_count, k_ra8_tz_sau_rlar_addr, k_ra8_tz_sau_rlar_enable, k_ra8_tz_sau_rlar_nsc, and k_ra8_tz_sau_rnr_addr.
Referenced by ra8_trustzone_init(), and ra8_tz_secure_boot_sau_init().
|
static |
Write a 16-bit MMIO register (or capture on host).
On target the value is stored at addr. On host the PRCR_S write is captured in s_host and the unlock / relock counts are incremented based on the PRC4 bit.
| [in] | addr | Target address. |
| [in] | value | Value to write. |
Definition at line 340 of file ra8_tz_secure_boot.c.
References k_ra8_tz_prcr_s_prc4_open, and RA8_INTERNAL.
Referenced by ra8_tz_secure_boot_security_init().
|
static |
Write a 32-bit MMIO register (or capture on host).
On target the value is stored directly into the MMIO register at addr. On host (RA8_OFF_TARGET) the value is captured in s_host so unit tests can inspect the write.
| [in] | addr | Target address. |
| [in] | value | Value to write. |
Definition at line 263 of file ra8_tz_secure_boot.c.
References k_ra8_tz_ipcpar_addr, k_ra8_tz_ipcsar_addr, k_ra8_tz_sau_ctrl_addr, k_ra8_tz_scb_vtor_ns_addr, and RA8_INTERNAL.
Referenced by internal_sau_set_region(), ra8_trustzone_init(), ra8_tz_secure_boot_jump_ns(), ra8_tz_secure_boot_sau_init(), and ra8_tz_secure_boot_security_init().
|
nodiscard |
Read the NS image's self-describing signed-body length.
Reads the ra8_ns_rot_header_t the NS linker embedded at k_ra8_tz_ns_rot_header_offset from ns_vector_table and returns its body_len field after confirming the header magic. This is the BLXNS boundary's analog of the DFU header's body-length word on the copy-to-run boundary: it tells the root-of-trust gate exactly how many bytes to hash and where the appended ra8_rot_trailer_t begins (ns_vector_table + body_len).
Reading body_len from the untrusted NS image is safe: a lie about it only changes which bytes are hashed, and no attacker can forge a valid ECDSA-P256 signature over any body without the held-out private key – so a wrong length simply default-denies at the signature check.
| [in] | ns_vector_table | Base of the NS image (its vector table). May be NULL (handled: returns 0). |
| 0 | ns_vector_table is NULL, or the header magic is wrong (no RoT header present) – the caller must NOT BLXNS. |
| non-zero | The body_len recorded in the NS RoT header. |
Definition at line 510 of file ra8_tz_secure_boot.c.
References ra8_ns_rot_header_t::body_len, k_ra8_tz_ns_rot_header_magic, k_ra8_tz_ns_rot_header_offset, ra8_log_error, and s_tag.
Referenced by internal_ns_verify_or_deny().
| ra8_tz_secure_boot_step_t ra8_tz_secure_boot_get_step | ( | void | ) |
Read the boot progress counter (debug / test).
Returns the most-recent ra8_tz_secure_boot_step_t value stored in the internal progress counter. Useful for J-Link memprobe scripts on the bench and for unit-test assertions on the host.
| k_ra8_tz_secure_boot_step_idle | Pre-run. |
| k_ra8_tz_secure_boot_step_sau_done | SAU init complete. |
| k_ra8_tz_secure_boot_step_ipcsar_written | IPCSAR landed. |
| k_ra8_tz_secure_boot_step_branched | BLXNS executed. |
Definition at line 691 of file ra8_tz_secure_boot.c.
References s_step.
Referenced by ra8_trustzone_init().
| uint32_t ra8_tz_secure_boot_host_blxns_target | ( | void | ) |
Read the captured BLXNS target (host / test).
Host-only accessor: returns the NS reset vector that ra8_tz_secure_boot_jump_ns was last asked to branch to. On target builds this returns 0 because BLXNS does not return.
| 0 | BLXNS not yet armed (or running on target). |
| non-zero | NS reset vector that was loaded for BLXNS. |
Definition at line 233 of file ra8_tz_secure_boot.c.
| void ra8_tz_secure_boot_host_reset | ( | void | ) |
Reset the host-side state for unit-test fixtures.
Host-only helper that clears the fake PRCR_S / IPCSAR / IPCPAR captures and the BLXNS target so each test starts from a known baseline. Cross-compiled (target) builds expose the symbol but the body is empty.
Definition at line 225 of file ra8_tz_secure_boot.c.
References s_tag.
|
nodiscard |
Switch to NS state and jump to the NS image's reset vector.
Reads the initial-SP slot of the NS vector table into MSP_NS, sets VTOR_NS to ns_vector_table, then performs a BLXNS to the reset-vector slot. The function is declared [[noreturn]] and does not return on hardware.
On target, a root-of-trust gate runs BEFORE VTOR_NS is armed and BEFORE the BLXNS: ra8_rot_verify_image must authenticate the Non-Secure image (SHA-256 + ECDSA-P256) against the provisioned root public key. This is default-deny – any failure (missing / malformed signature trailer, tampered body, or an invalid signature) returns the verify error and the function does NOT branch into the NS world. The signed body length is read from the NS image's own ra8_ns_rot_header_t (emitted by the NS linker at k_ra8_tz_ns_rot_header_offset, see ra8_tz_ns_signed_body_len), and the ra8_rot_trailer_t sits immediately after that body at ns_vector_table + body_len – the same self-describing [ body ] [ trailer ] layout the copy-to-run boundary uses.
On the host (RA8_OFF_TARGET defined) the function stamps the progress counter, sets s_ra8_tz_secure_boot_blxns_target to the supplied reset vector, and returns k_ra8_ok so unit tests can assert the documented transition state; the gate's decision logic is covered directly in tests/security/src/test_ra8_root_of_trust.c.
| [in] | ns_vector_table | Pointer to the NS image's vector table. |
| k_ra8_ok | On host: BLXNS state captured. |
| k_ra8_err_null_ptr | ns_vector_table is NULL. |
| k_ra8_err_invalid_arg | ns_vector_table is not 4-byte aligned, or the reset-vector slot holds an obviously bogus value (0 or 0xFFFFFFFF). |
| k_ra8_err_* | On target: the root-of-trust gate denied the NS image (e.g. k_ra8_err_crc_mismatch for a bad signature) – BLXNS is not performed. |
Definition at line 612 of file ra8_tz_secure_boot.c.
References internal_ns_verify_or_deny(), internal_write32(), k_ra8_err_invalid_arg, k_ra8_ok, k_ra8_tz_scb_vtor_ns_addr, k_ra8_tz_secure_boot_step_blxns_armed, k_ra8_tz_secure_boot_step_branched, RA8_CHECK_NULL_PTR, ra8_log_error, ra8_log_error_val, s_step, and s_tag.
Referenced by main(), ra8_trustzone_init(), and ra8_tz_secure_boot_run().
|
nodiscard |
Run the full secure-boot sequence and (on target) BLXNS.
Convenience wrapper: ra8_tz_secure_boot_sau_init -> ra8_tz_secure_boot_security_init -> ra8_tz_secure_boot_jump_ns, returning the first non-OK status.
| [in] | ipcsar_value | Forwarded to security_init. |
| [in] | ipcpar_value | Forwarded to security_init. |
| [in] | ns_vector_table | Forwarded to jump_ns. |
| k_ra8_ok | On host happy path (BLXNS captured). |
| k_ra8_err_null_ptr | ns_vector_table is NULL. |
| k_ra8_err_not_supported | SAU_TYPE.SREGION < 5. |
| k_ra8_err_invalid_arg | NS vector table mis-aligned / invalid. |
Definition at line 671 of file ra8_tz_secure_boot.c.
References k_ra8_ok, RA8_CHECK_NULL_PTR, ra8_tz_secure_boot_jump_ns(), ra8_tz_secure_boot_sau_init(), ra8_tz_secure_boot_security_init(), and s_tag.
|
nodiscard |
Programme the SAU regions documented in ra8_tz_sau_region_t.
Equivalent to the FSP R_BSP_SAUInit function: writes each region's RBAR / RLAR, then enables the SAU with ALLNS = 0. Does NOT touch CPSCU or jump to the NS image – callers issue ra8_tz_secure_boot_security_init and ra8_tz_secure_boot_jump_ns separately so unit tests can exercise each phase in isolation.
| k_ra8_ok | SAU programmed and enabled. |
| k_ra8_err_not_supported | SAU_TYPE.SREGION < 5. |
Definition at line 441 of file ra8_tz_secure_boot.c.
References internal_dsb(), internal_isb(), internal_read32(), internal_sau_set_region(), internal_write32(), k_ra8_err_not_supported, k_ra8_ok, k_ra8_tz_part_code_nsc_base, k_ra8_tz_part_code_nsc_limit, k_ra8_tz_part_ns_mram_base, k_ra8_tz_part_ns_mram_limit, k_ra8_tz_part_ns_per_base, k_ra8_tz_part_ns_per_limit, k_ra8_tz_part_ns_sram_base, k_ra8_tz_part_ns_sram_limit, k_ra8_tz_part_sram_nsc_base, k_ra8_tz_part_sram_nsc_limit, k_ra8_tz_sau_ctrl_addr, k_ra8_tz_sau_ctrl_enable, k_ra8_tz_sau_region_code_nsc, k_ra8_tz_sau_region_count, k_ra8_tz_sau_region_ns_mram, k_ra8_tz_sau_region_ns_periph, k_ra8_tz_sau_region_ns_sram, k_ra8_tz_sau_region_sram_nsc, k_ra8_tz_sau_type_addr, k_ra8_tz_sau_type_mask, k_ra8_tz_secure_boot_step_sau_done, ra8_log_error, s_step, and s_tag.
Referenced by ra8_trustzone_init(), and ra8_tz_secure_boot_run().
|
nodiscard |
Unlock PRCR_S.PRC4 and write IPCSAR + IPCPAR.
Writes ipcsar_value to CPSCU.IPCSAR and ipcpar_value to CPSCU.IPCPAR after first opening the PRCR_S.PRC4 write-protect gate (HUM Ch 13.2.1 "PRCR_S" – key 0xA510 at address 0x4001E3FA). The gate is closed again before the function returns.
For the cpu1_pingpong_ipc app the canonical value is ipcsar_value = 0x00050000, which sets SAIPCIR0 (IPC0 channel 0, CPU1 -> CPU0) and SAIPCIR2 (IPC1 channel 0, CPU0 -> CPU1) – the two channels CPU1 (always-NS) must reach. ipcpar_value stays at 0 so the channels remain Privileged-only.
| [in] | ipcsar_value | Value to write into CPSCU.IPCSAR. |
| [in] | ipcpar_value | Value to write into CPSCU.IPCPAR. |
| k_ra8_ok | Always (the unlock + write + relock sequence cannot fail in software; bench bring-up may still observe read-back mismatches if the chip's CPSCU is in an unexpected state). |
Definition at line 481 of file ra8_tz_secure_boot.c.
References internal_dsb(), internal_write16(), internal_write32(), k_ra8_ok, k_ra8_tz_ipcpar_addr, k_ra8_tz_ipcsar_addr, k_ra8_tz_prcr_s_addr, k_ra8_tz_prcr_s_close, k_ra8_tz_prcr_s_open, k_ra8_tz_secure_boot_step_ipcsar_written, k_ra8_tz_secure_boot_step_prcr_relocked, k_ra8_tz_secure_boot_step_prcr_unlocked, and s_step.
Referenced by ra8_trustzone_init(), and ra8_tz_secure_boot_run().
|
static |
Progress counter exposed via ra8_tz_secure_boot_get_step.
Stamped at each forward-progress milestone in the secure boot. Bench scripts read this through SWD to find out which phase wedged when bring-up never reaches the NS image.
Definition at line 58 of file ra8_tz_secure_boot.c.
Referenced by ra8_tz_secure_boot_get_step(), ra8_tz_secure_boot_jump_ns(), ra8_tz_secure_boot_sau_init(), and ra8_tz_secure_boot_security_init().
|
static |
Logger tag for the secure-boot module.
Component identifier used by ra8_log_* so secure-boot log lines are easy to grep for in JTAG-captured RTT output.
Definition at line 45 of file ra8_tz_secure_boot.c.