ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_tz_secure_boot.c
Go to the documentation of this file.
1
22
23#include "ra8_tz_secure_boot.h"
24
25#include <stdint.h>
26
27#include "ra8_attributes.h"
28#include "ra8_check.h"
29#include "ra8_err.h"
30#include "ra8_log.h"
31#ifdef RA8_ENABLE_ROOT_OF_TRUST
32#include "ra8_rot.h"
33#endif
34
45static const char* s_tag = "TZBOOT";
46
59
60/* =============================================================================
61 * Address constants (verified against HUM Ch 13 + Ch 3)
62 * =============================================================================
63 */
64
77typedef enum : uintptr_t {
78 k_ra8_tz_sau_ctrl_addr = 0xE000EDD0UL,
79 k_ra8_tz_sau_type_addr = 0xE000EDD4UL,
80 k_ra8_tz_sau_rnr_addr = 0xE000EDD8UL,
81 k_ra8_tz_sau_rbar_addr = 0xE000EDDCUL,
82 k_ra8_tz_sau_rlar_addr = 0xE000EDE0UL,
84 k_ra8_tz_ipcsar_addr = 0x40008610UL,
85 k_ra8_tz_ipcpar_addr = 0x40008614UL,
86 k_ra8_tz_prcr_s_addr = 0x4001E3FAUL,
88
98typedef enum : uint32_t {
102 k_ra8_tz_sau_rlar_nsc = 0x00000002U,
105
121
133typedef enum : uint32_t {
142 /* NS peripheral region needs to cover BOTH the standard Cortex-M
143 * peripheral window at 0x40000000 (where IPC lives at 0x40020000)
144 * AND the alias window at 0x50000000. With the original 0x5xxxxxxx-
145 * only region, CPU1 (NS-only per SECEXT-disabled silicon) cannot
146 * reach any IPC channel even after IPCSAR=0x50000 makes channels
147 * 0/2 NS-attributed at the peripheral level -- the SAU still has
148 * to permit the underlying peripheral address as NS. Bench
149 * evidence on 2026-05-27: with 0x5xxxxxxx-only the ping-pong
150 * counters stay at zero (CPU0 sends, CPU1 SecureFaults on recv);
151 * extending the region down to 0x40000000 unblocks the round-trip. */
155
156#ifdef RA8_OFF_TARGET
157
158/* =============================================================================
159 * Host-side captures
160 * =============================================================================
161 *
162 * On the host build the SAU / CPSCU / VTOR writes go into the
163 * captures below so unit tests can assert on the documented behaviour
164 * without touching real memory.
165 */
166
178typedef struct {
179 uint32_t sau_ctrl;
180 uint32_t sau_region_base[k_ra8_tz_sau_region_count];
181 uint32_t sau_region_limit[k_ra8_tz_sau_region_count];
182 uint8_t sau_region_nsc[k_ra8_tz_sau_region_count];
183 uint16_t prcr_s_last;
184 uint8_t prcr_unlock_count;
185 uint8_t prcr_relock_count;
186 uint32_t ipcsar_value;
187 uint32_t ipcpar_value;
188 uint32_t blxns_target;
189 uint32_t blxns_msp_ns;
190 uint32_t vtor_ns;
191} ra8_tz_secure_boot_host_state_t;
192
202static ra8_tz_secure_boot_host_state_t s_host = {};
203
205{
206 /* Pre 1: the host state struct lives in BSS so its address is always
207 * non-NULL on any hosted environment we run on. */
208 /* Pre 2: ``s_tag`` is a static const string used to silence the
209 * unused-symbol warning on the target build. */
210 (void)s_tag;
211 s_host = (ra8_tz_secure_boot_host_state_t){};
213 /* Post 1: tests get a deterministic baseline. */
214 /* Post 2: progress counter is back at idle. */
215}
216
218{
219 /* Pre + post: pure accessor; no state change. */
220 return s_host.blxns_target;
221}
222
223#else /* !RA8_OFF_TARGET */
224
226{
227 /* Pre + post: target build exposes the symbol but the body is a
228 * no-op so unit-test fixtures that link against the target stub do
229 * not crash. */
230 (void)s_tag;
231}
232
234{
235 /* Pre + post: target build returns 0 because BLXNS never returns. */
236 return 0U;
237}
238
239#endif /* RA8_OFF_TARGET */
240
241/* =============================================================================
242 * Small register helpers (host-aware)
243 * =============================================================================
244 */
245
263RA8_INTERNAL static void internal_write32(uintptr_t addr, uint32_t value)
264{
265#ifdef RA8_OFF_TARGET
266 if (addr == (uintptr_t)k_ra8_tz_ipcsar_addr) {
267 s_host.ipcsar_value = value;
268 } else if (addr == (uintptr_t)k_ra8_tz_ipcpar_addr) {
269 s_host.ipcpar_value = value;
270 } else if (addr == (uintptr_t)k_ra8_tz_scb_vtor_ns_addr) {
271 s_host.vtor_ns = value;
272 } else if (addr == (uintptr_t)k_ra8_tz_sau_ctrl_addr) {
273 s_host.sau_ctrl = value;
274 }
275 /* SAU RBAR / RLAR writes are routed through internal_sau_set_region. */
276#else
277 /* HUM Ch 3.2.1 "IPCSAR" p 205 and HUM Ch 13.2.1 "PRCR_S" p 521 for
278 * the secure-only writes routed through this helper. Generic 32-bit
279 * MMIO store; the called sites cite their own register page. */
280 *(volatile uint32_t*)addr = value;
281#endif
282}
283
304RA8_INTERNAL static uint32_t internal_read32(uintptr_t addr)
305{
306#ifdef RA8_OFF_TARGET
307 if (addr == (uintptr_t)k_ra8_tz_sau_type_addr) {
308 /* Cortex-M85 implements 8 SAU regions; tests rely on that. */
309 return 8U;
310 }
311 if (addr == (uintptr_t)k_ra8_tz_ipcsar_addr) {
312 return s_host.ipcsar_value;
313 }
314 return 0U;
315#else
316 /* HUM Ch 3.2.1 "IPCSAR" p 205 -- only IPCSAR is ever read back here
317 * after the write; everything else (SAU_TYPE) is architectural. */
318 return *(volatile uint32_t*)addr;
319#endif
320}
321
340RA8_INTERNAL static void internal_write16(uintptr_t addr, uint16_t value)
341{
342#ifdef RA8_OFF_TARGET
343 s_host.prcr_s_last = value;
344 if ((value & (uint16_t)k_ra8_tz_prcr_s_prc4_open) != 0U) {
345 s_host.prcr_unlock_count = (uint8_t)(s_host.prcr_unlock_count + 1U);
346 } else {
347 s_host.prcr_relock_count = (uint8_t)(s_host.prcr_relock_count + 1U);
348 }
349 (void)addr;
350#else
351 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
352 *(volatile uint16_t*)addr = value;
353#endif
354}
355
369RA8_INTERNAL static inline void internal_dsb(void)
370{
371#ifndef RA8_OFF_TARGET
372 __asm__ volatile("dsb 0xF" ::: "memory");
373#endif
374}
375
389RA8_INTERNAL static inline void internal_isb(void)
390{
391#ifndef RA8_OFF_TARGET
392 __asm__ volatile("isb 0xF" ::: "memory");
393#endif
394}
395
396/* =============================================================================
397 * SAU region programming
398 * =============================================================================
399 */
400
421RA8_INTERNAL static void
422internal_sau_set_region(uint8_t region, uint32_t base, uint32_t limit, bool is_nsc)
423{
424 internal_write32(k_ra8_tz_sau_rnr_addr, (uint32_t)region);
426 uint32_t rlar = limit | (uint32_t)k_ra8_tz_sau_rlar_enable;
427 if (is_nsc) {
428 rlar |= (uint32_t)k_ra8_tz_sau_rlar_nsc;
429 }
431
432#ifdef RA8_OFF_TARGET
433 if ((uint32_t)region < (uint32_t)k_ra8_tz_sau_region_count) {
434 s_host.sau_region_base[region] = base;
435 s_host.sau_region_limit[region] = limit;
436 s_host.sau_region_nsc[region] = (uint8_t)(is_nsc ? 1U : 0U);
437 }
438#endif
439}
440
442{
443 /* Pre: SAU_TYPE.SREGION must report >= 5 implemented regions. */
444 const uint32_t sau_type = internal_read32(k_ra8_tz_sau_type_addr);
445 if ((sau_type & (uint32_t)k_ra8_tz_sau_type_mask) < (uint32_t)k_ra8_tz_sau_region_count) {
446 ra8_log_error(s_tag, "SAU_TYPE.SREGION below required count");
448 }
449
453 /*is_nsc=*/true);
457 /*is_nsc=*/false);
461 /*is_nsc=*/true);
465 /*is_nsc=*/false);
469 /*is_nsc=*/false);
470
471 internal_dsb();
473 internal_dsb();
474 internal_isb();
475
476 /* Post: SAU enabled with the canonical layout, default-deny. */
478 return k_ra8_ok;
479}
480
481ra8_err_t ra8_tz_secure_boot_security_init(uint32_t ipcsar_value, uint32_t ipcpar_value)
482{
483 /* Pre 1: caller must be in Secure state (architectural; cannot be
484 * checked from C, documented in the header). */
485 /* Pre 2: PRCR_S unlock must observe the documented key + bit
486 * pattern, otherwise the chip silently drops the write. */
487
488 /* Open the PRC4 gate so the next IPCSAR / IPCPAR writes land. */
489 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
492
493 /* HUM Ch 3.2.1 "IPCSAR" p 205-207 */
495 /* HUM Ch 3.2.2 "IPCPAR" p 208-209 */
498
499 /* Close the PRC4 gate to restore write-protect on CPSCU. */
500 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
503
504 internal_dsb();
505 /* Post 1: IPCSAR landed (verifiable via JTAG read-back). */
506 /* Post 2: PRCR_S.PRC4 clear (write-protect restored). */
507 return k_ra8_ok;
508}
509
510uint32_t ra8_tz_ns_signed_body_len(const uint32_t* ns_vector_table)
511{
512 /* Validation 1: reject a NULL image base (returns the deny sentinel 0). */
513 if (ns_vector_table == nullptr) {
514 ra8_log_error(s_tag, "ns_vector_table is NULL");
515 return 0U;
516 }
517 /* The NS linker emits an ::ra8_ns_rot_header_t at a fixed small offset from the
518 * NS base (just past the 16-slot ARMv8-M vector table -- see
519 * ::k_ra8_tz_ns_rot_header_offset), self-describing the signed body length.
520 * This is a plain memory read of the (already-flashed/copied) NS image; there
521 * is no MMIO register access here, so no HUM citation applies. The reinterpret
522 * casts route through a named `const void*` seam (as `ra8_epub` does): a direct
523 * `const uint8_t* -> ra8_ns_rot_header_t*` cast trips -Wcast-align, and a
524 * one-expression `(T*)(const void*)p` cast trips bugprone-casting-through-void. */
525 const void* const ns_image = ns_vector_table;
526 const uint8_t* base = (const uint8_t*)ns_image;
527 const void* const header_at = base + (uintptr_t)k_ra8_tz_ns_rot_header_offset;
528 const ra8_ns_rot_header_t* header = (const ra8_ns_rot_header_t*)header_at;
529 /* Validation 2: reject a missing / wrong-magic header (returns 0 -> deny). */
530 if (header->magic != (uint32_t)k_ra8_tz_ns_rot_header_magic) {
531 ra8_log_error(s_tag, "NS RoT header magic mismatch");
532 return 0U;
533 }
534 return header->body_len;
535}
536
589RA8_INTERNAL static ra8_err_t internal_ns_verify_or_deny(const uint32_t* ns_vector_table)
590{
591 RA8_CHECK_NULL_PTR(ns_vector_table, s_tag, "ns_vector_table");
592#if !defined(RA8_OFF_TARGET) && defined(RA8_ENABLE_ROOT_OF_TRUST)
593 const uint32_t ns_body_len = ra8_tz_ns_signed_body_len(ns_vector_table);
594 if (ns_body_len == 0U) {
595 ra8_log_error(s_tag, "NS RoT header missing/invalid -- denying BLXNS");
597 }
598 const ra8_rot_trailer_t* ns_trailer = ra8_rot_trailer_after(ns_vector_table, ns_body_len);
599 if (ns_trailer == nullptr) {
600 ra8_log_error(s_tag, "NS RoT body_len out of range -- denying BLXNS");
602 }
603 return ra8_rot_verify_image((const uint8_t*)(const void*)ns_vector_table,
604 ns_body_len,
605 ns_trailer);
606#else
607 (void)ns_vector_table;
608 return k_ra8_ok; /* root of trust disabled (or host build): no verification */
609#endif /* !RA8_OFF_TARGET && RA8_ENABLE_ROOT_OF_TRUST */
610}
611
612ra8_err_t ra8_tz_secure_boot_jump_ns(const uint32_t* ns_vector_table)
613{
614 RA8_CHECK_NULL_PTR(ns_vector_table, s_tag, "ns_vector_table");
615 /* Pre 2: 4-byte alignment. */
616 if (((uintptr_t)ns_vector_table & 0x3U) != 0U) {
617 ra8_log_error(s_tag, "ns_vector_table misaligned");
619 }
620
621 const uint32_t initial_sp = ns_vector_table[0];
622 const uint32_t reset_entry = ns_vector_table[1];
623
624 /* Reject obviously bogus reset vectors -- 0 (all zeros) or
625 * 0xFFFFFFFF (erased MRAM). FSP guards the same way. */
626 if (reset_entry == 0U || reset_entry == UINT32_MAX) {
627 ra8_log_error_val(s_tag, "NS reset vector invalid", reset_entry);
629 }
630
631 /* Root-of-trust gate before BLXNS: deny the jump on a failed authentication
632 * (no-op when RA8_ENABLE_ROOT_OF_TRUST is off -- see internal_ns_verify_or_deny). */
633 const ra8_err_t auth_err = internal_ns_verify_or_deny(ns_vector_table);
634 if (auth_err != k_ra8_ok) {
635 ra8_log_error(s_tag, "NS image authentication failed -- denying BLXNS");
636 return auth_err;
637 }
638
639 /* HUM Ch 4 "Option Setting Memory" + ARMv8-M ARM B3.2.4: VTOR_NS
640 * accessed via the 0xE002... NS alias of SCB.VTOR (=0xE002ED08). */
641 internal_write32(k_ra8_tz_scb_vtor_ns_addr, (uint32_t)(uintptr_t)ns_vector_table);
643
644#ifdef RA8_OFF_TARGET
645 s_host.blxns_target = reset_entry;
646 s_host.blxns_msp_ns = initial_sp;
648 return k_ra8_ok;
649#else
650 /* ARMv8-M MSR_NS / BLXNS sequence -- set MSP_NS, then branch into
651 * the NS world via BLXNS. The compiler does NOT emit BLXNS through
652 * a regular function-pointer call; we need inline asm.
653 *
654 * BLXNS switches to Non-Secure state only when bit[0] of the target
655 * register is 0; bit[0] == 1 keeps the call Secure (it is the
656 * function-descriptor "Secure" marker, not the Thumb bit). The NS reset
657 * vector carries the Thumb bit set, so it MUST be cleared here -- otherwise
658 * the "NS" image executes in Secure state on the Secure stack and every
659 * NS-pointer cmse check in the NSC veneers misfires. */
660 const uint32_t ns_entry = reset_entry & ~(uint32_t)1U;
661 __asm__ volatile("msr msp_ns, %0\n"
662 "blxns %1\n"
663 :
664 : "r"(initial_sp), "r"(ns_entry)
665 : "memory");
666 /* Unreachable on target. */
667 return k_ra8_ok;
668#endif
669}
670
671ra8_err_t ra8_tz_secure_boot_run(uint32_t ipcsar_value,
672 uint32_t ipcpar_value,
673 const uint32_t* ns_vector_table)
674{
675 RA8_CHECK_NULL_PTR(ns_vector_table, s_tag, "ns_vector_table");
676
678 if (err != k_ra8_ok) {
679 return err;
680 }
681
682 err = ra8_tz_secure_boot_security_init(ipcsar_value, ipcpar_value);
683 if (err != k_ra8_ok) {
684 return err;
685 }
686
687 /* Post: the next call BLXNS-es out and never returns on target. */
688 return ra8_tz_secure_boot_jump_ns(ns_vector_table);
689}
690
692{
693 /* Pre: progress counter lives in BSS so it is always readable. */
694 /* Pre: single 32-bit volatile load -- atomic on all targets. */
695 /* Post: returned value matches the most recent step write. */
696 /* Post: no state change. */
697 return s_step;
698}
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_not_supported
Requested feature not compiled in, not wired, or not supported by this MCU variant.
Definition ra8_err.h:180
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_error_val(tag, message, value)
RA8 log error val.
Definition ra8_log.h:337
#define ra8_log_error(tag, message)
RA8 log error.
Definition ra8_log.h:335
Root-of-trust signed-image verifier (SHA-256 + ECDSA-P256, default-deny).
ra8_err_t ra8_rot_verify_image(const uint8_t *body, uint32_t body_len, const ra8_rot_trailer_t *trailer)
Authenticate a signed image: SHA-256 + ECDSA-P256, default-deny.
const ra8_rot_trailer_t * ra8_rot_trailer_after(const void *image_base, uint32_t body_len)
Locate the trailer that immediately follows a signed image body.
ra8_tz_secure_boot_addr_t
Memory-mapped register addresses used by the secure-boot.
@ k_ra8_tz_sau_type_addr
SAU Type.
@ k_ra8_tz_prcr_s_addr
SYSC PRCR_S (16-bit).
@ k_ra8_tz_sau_rbar_addr
Region Base.
@ k_ra8_tz_scb_vtor_ns_addr
VTOR Non-Secure alias.
@ k_ra8_tz_sau_ctrl_addr
SAU Control.
@ k_ra8_tz_sau_rnr_addr
Region Num.
@ k_ra8_tz_sau_rlar_addr
Region Lim.
@ k_ra8_tz_ipcsar_addr
CPSCU IPCSAR.
@ k_ra8_tz_ipcpar_addr
CPSCU IPCPAR.
static void internal_dsb(void)
Emit a Data Synchronisation Barrier (no-op on host).
ra8_tz_secure_boot_step_t ra8_tz_secure_boot_get_step(void)
Read the boot progress counter (debug / test).
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_sau_init(void)
Programme the SAU regions documented in ra8_tz_sau_region_t.
uint32_t ra8_tz_secure_boot_host_blxns_target(void)
Read the captured BLXNS target (host / test).
void ra8_tz_secure_boot_host_reset(void)
Reset the host-side state for unit-test fixtures.
static void internal_write32(uintptr_t addr, uint32_t value)
Write a 32-bit MMIO register (or capture on host).
ra8_tz_secure_boot_prcr_t
PRCR_S unlock key + per-group enable bits (HUM Ch 13.2.1).
@ 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).
@ k_ra8_tz_prcr_s_key
Unlock key (top byte).
ra8_tz_secure_boot_partition_t
Canonical SAU region base / limit addresses (HUM Ch 4).
@ k_ra8_tz_part_ns_sram_limit
RA8 TrustZone part ns SRAM limit.
@ k_ra8_tz_part_ns_mram_base
RA8 TrustZone part ns MRAM base.
@ k_ra8_tz_part_code_nsc_base
RA8 TrustZone part code NSC base.
@ k_ra8_tz_part_sram_nsc_limit
RA8 TrustZone part SRAM NSC limit.
@ k_ra8_tz_part_ns_per_limit
RA8 TrustZone part ns per limit.
@ k_ra8_tz_part_ns_sram_base
RA8 TrustZone part ns SRAM base.
@ k_ra8_tz_part_sram_nsc_base
RA8 TrustZone part SRAM NSC base.
@ k_ra8_tz_part_ns_per_base
RA8 TrustZone part ns per base.
@ k_ra8_tz_part_ns_mram_limit
RA8 TrustZone part ns MRAM limit.
@ k_ra8_tz_part_code_nsc_limit
RA8 TrustZone part code NSC limit.
static uint32_t internal_read32(uintptr_t addr)
Read a 32-bit MMIO register (or canned host value).
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 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_security_init(uint32_t ipcsar_value, uint32_t ipcpar_value)
Unlock PRCR_S.PRC4 and write IPCSAR + IPCPAR.
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_tz_secure_boot_sau_bit_t
Bit positions used to enable / configure each SAU region.
@ k_ra8_tz_sau_ctrl_allns
CTRL.ALLNS (kept 0).
@ k_ra8_tz_sau_ctrl_enable
CTRL.ENABLE.
@ k_ra8_tz_sau_rlar_enable
RLAR.ENABLE.
@ k_ra8_tz_sau_rlar_nsc
RLAR.NSC.
@ k_ra8_tz_sau_type_mask
TYPE.SREGION lower 8b.
static void internal_isb(void)
Emit an Instruction Synchronisation Barrier (no-op on host).
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.
static void internal_write16(uintptr_t addr, uint16_t value)
Write a 16-bit MMIO register (or capture on host).
static volatile ra8_tz_secure_boot_step_t s_step
Progress counter exposed via ra8_tz_secure_boot_get_step.
FSP-style TrustZone secure-boot for the Cortex-M85 (CPU0).
@ k_ra8_tz_ns_rot_header_offset
Offset after the 16-slot NS vectors.
@ k_ra8_tz_ns_rot_header_magic
ASCII "NSR1" (little-endian).
@ k_ra8_tz_sau_region_ns_periph
Non-Secure peripheral window.
@ k_ra8_tz_sau_region_code_nsc
NSC alias for code-flash veneers.
@ k_ra8_tz_sau_region_sram_nsc
NSC alias for SRAM veneers.
@ k_ra8_tz_sau_region_count
Number of programmed regions.
@ k_ra8_tz_sau_region_ns_mram
Non-Secure upper MRAM (NS image).
@ k_ra8_tz_sau_region_ns_sram
Non-Secure upper SRAM (NS data).
ra8_tz_secure_boot_step_t
Progress markers stamped into g_ra8_tz_secure_boot_step.
@ k_ra8_tz_secure_boot_step_sau_done
SAU regions programmed.
@ k_ra8_tz_secure_boot_step_ipcsar_written
IPCSAR write landed.
@ k_ra8_tz_secure_boot_step_prcr_unlocked
PRCR_S.PRC4 set.
@ k_ra8_tz_secure_boot_step_blxns_armed
MSP_NS / VTOR set up.
@ k_ra8_tz_secure_boot_step_branched
BLXNS executed (host).
@ k_ra8_tz_secure_boot_step_prcr_relocked
PRCR_S.PRC4 cleared.
@ k_ra8_tz_secure_boot_step_idle
Pre-run sentinel.
Self-describing RoT header the NS linker embeds in the NS image.
uint32_t body_len
Signed body length in bytes (trailer at base+len).
Authenticity trailer appended after a signed image body.
Definition ra8_rot.h:150