ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
trustzone_init.c
Go to the documentation of this file.
1
55
56#include "trustzone_init.h"
57
58#include <stdint.h>
59
60#include "ra8_board_ek_ra8d2.h"
61#include "ra8_cgc.h"
62#include "ra8_err.h"
63#include "ra8_gpio_constants.h"
64#include "ra8_pin_validator.h"
65#include "ra8_port_constants.h"
66#include "ra8_port_utils.h"
67#include "ra8_tz_secure_boot.h"
68
69/* Bounds of the NSC veneer stubs (.gnu.sgstubs) in this (Secure) image. */
70extern uint32_t g_ra8_ls_sgstubs_start;
71extern uint32_t g_ra8_ls_sgstubs_end;
72
86typedef enum : uintptr_t {
87 k_tz_ns_load_base = 0x02080000U,
88 k_tz_ns_run_base = 0x32100000U,
89 k_tz_ns_copy_size = 0x00030000U,
91
92#ifdef RA8_TRUSTZONE_ENABLE
93
105typedef enum : uintptr_t {
106 k_tz_sau_ctrl_addr = 0xE000EDD0U,
107 k_tz_sau_type_addr = 0xE000EDD4U,
108 k_tz_sau_rnr_addr = 0xE000EDD8U,
109 k_tz_sau_rbar_addr = 0xE000EDDCU,
110 k_tz_sau_rlar_addr = 0xE000EDE0U,
111 k_tz_sramsabar0_addr = 0x40008400U,
112 k_tz_prcr_s_addr = 0x4001E3FAU,
113 k_tz_psarb_addr = 0x40204004U,
114} tz_reg_addr_t;
115
123typedef enum : uint32_t {
124 k_tz_sau_ctrl_enable = 0x00000001U,
125 k_tz_sau_rlar_enable = 0x00000001U,
126 k_tz_sau_rlar_nsc = 0x00000002U,
127 k_tz_sau_limit_mask = 0xFFFFFFE0U,
128 k_tz_sau_type_mask = 0x000000FFU,
129 k_tz_psarb_usbfs_ns = 0x00000800U,
130 k_tz_psarb_usbhs_ns = 0x00001000U,
131 k_tz_psarb_usb_ns = 0x00001800U,
132 k_tz_psarb_readback_spins = 1000U,
133} tz_field_t;
134
147typedef enum : uint16_t {
148 k_tz_usb_pin_vbus = (uint16_t)k_ra8_board_usbfs_pin_vbus,
149 k_tz_usb_pin_vbusen = (uint16_t)k_ra8_board_usbfs_pin_vbusen,
150 k_tz_usb_pin_dp = (uint16_t)k_ra8_board_usbfs_pin_dp,
151 k_tz_usb_pin_dm = (uint16_t)k_ra8_board_usbfs_pin_dm,
152 k_tz_usb_pin_hs_vbus = (uint16_t)k_ra8_board_usbhs_pin_vbus,
153 k_tz_usb_pin_hs_pwr = (uint16_t)k_ra8_board_usbhs_pin_pwr,
154} tz_usb_pin_t;
155
166volatile uint32_t g_tz_usb_psarb_readback;
167
176volatile uint32_t g_tz_usb_pins_err;
177
190volatile uint32_t g_tz_usb_expander_err;
191
205volatile uint32_t g_tz_jump_ns_err;
206
213typedef enum : uint16_t {
214 k_tz_prcr_s_open = 0xA510U,
215 k_tz_prcr_s_close = 0xA500U,
216} tz_prcr_t;
217
228typedef enum : uint32_t {
229 k_tz_sau_min_regions = 4U,
230 k_tz_ns_code_base = 0x10000000U,
231 k_tz_ns_code_limit = 0x1FFFFFE0U,
232 k_tz_ns_sram_base = 0x30000000U,
233 k_tz_ns_sram_limit = 0x3FFFFFE0U,
234 k_tz_ns_per_base = 0x50000000U,
235 k_tz_ns_per_limit = 0xDFFFFFE0U,
236 k_tz_sramsabar0_val = 0x00080000U,
237 k_tz_sramsabar1_val = 0x00100000U,
238 k_tz_sramsabar2_val = 0x00100000U,
239 k_tz_sramsabar3_val = 0x001A0000U,
240} tz_partition_t;
241
245typedef enum : uint8_t {
246 k_tz_region_nsc = 0U,
247 k_tz_region_ns_code = 1U,
248 k_tz_region_ns_sram = 2U,
249 k_tz_region_ns_per = 3U,
250} tz_region_t;
251
264static inline void tz_write32(uintptr_t addr, uint32_t value)
265{
266 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 -- generic
267 * secure-MMIO store; SAU / CPSCU callers cite their own page below. */
268 *(volatile uint32_t*)addr = value;
269}
270
283static inline uint32_t tz_read32(uintptr_t addr)
284{
285 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 */
286 return *(volatile uint32_t*)addr;
287}
288
302static void tz_sau_set_region(uint8_t region, uint32_t base, uint32_t limit, bool is_nsc)
303{
304 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 */
305 tz_write32(k_tz_sau_rnr_addr, (uint32_t)region);
306 tz_write32(k_tz_sau_rbar_addr, base & (uint32_t)k_tz_sau_limit_mask);
307 uint32_t rlar = (limit & (uint32_t)k_tz_sau_limit_mask) | (uint32_t)k_tz_sau_rlar_enable;
308 if (is_nsc) {
309 rlar |= (uint32_t)k_tz_sau_rlar_nsc;
310 }
311 tz_write32(k_tz_sau_rlar_addr, rlar);
312}
313
330static void tz_sram_ns_boundary(void)
331{
332 /* Open PRC4 so the CPSCU SRAMSABAR writes below land. */
333 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
334 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_open;
335
336 /* HUM Ch 58.2 "SRAMSABARn : SRAM Security Attribute Boundary Address
337 * Register" p 3527 -- boundary = start address of the NS region; below
338 * = Secure, at/above = Non-secure. */
339 tz_write32(k_tz_sramsabar0_addr + (0U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar0_val);
340 tz_write32(k_tz_sramsabar0_addr + (1U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar1_val);
341 tz_write32(k_tz_sramsabar0_addr + (2U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar2_val);
342 tz_write32(k_tz_sramsabar0_addr + (3U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar3_val);
343
344 /* Re-lock PRC4 (restore CPSCU write-protect). */
345 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
346 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_close;
347}
348
368static ra8_err_t tz_sau_program(void)
369{
370 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 -- need at
371 * least 4 implemented regions for this layout. */
372 const uint32_t sau_type = tz_read32(k_tz_sau_type_addr);
373 if ((sau_type & (uint32_t)k_tz_sau_type_mask) < (uint32_t)k_tz_sau_min_regions) {
375 }
376
377 /* RLAR limit is the LAST byte of the veneer block (end - 1); the helper
378 * masks it to the 32-byte SAU region quantum. */
379 const uint32_t nsc_base = (uint32_t)(uintptr_t)&g_ra8_ls_sgstubs_start;
380 const uint32_t nsc_limit = (uint32_t)(uintptr_t)&g_ra8_ls_sgstubs_end - 1U;
381 tz_sau_set_region((uint8_t)k_tz_region_nsc, nsc_base, nsc_limit, /*is_nsc=*/true);
382 tz_sau_set_region((uint8_t)k_tz_region_ns_code,
383 (uint32_t)k_tz_ns_code_base,
384 (uint32_t)k_tz_ns_code_limit,
385 /*is_nsc=*/false);
386 tz_sau_set_region((uint8_t)k_tz_region_ns_sram,
387 (uint32_t)k_tz_ns_sram_base,
388 (uint32_t)k_tz_ns_sram_limit,
389 /*is_nsc=*/false);
390 tz_sau_set_region((uint8_t)k_tz_region_ns_per,
391 (uint32_t)k_tz_ns_per_base,
392 (uint32_t)k_tz_ns_per_limit,
393 /*is_nsc=*/false);
394
395 __asm__ volatile("dsb 0xF" ::: "memory");
396 /* Enable the SAU with ALLNS = 0 (default-deny). */
397 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 */
398 tz_write32(k_tz_sau_ctrl_addr, (uint32_t)k_tz_sau_ctrl_enable);
399 __asm__ volatile("dsb 0xF" ::: "memory");
400 __asm__ volatile("isb" ::: "memory");
401 return k_ra8_ok;
402}
403
421static void tz_copy_ns_image(void)
422{
423 const uintptr_t src_start = (uintptr_t)k_tz_ns_load_base;
424 const uintptr_t src_end = src_start + (uintptr_t)k_tz_ns_copy_size;
425 uintptr_t dst = (uintptr_t)k_tz_ns_run_base;
426 for (uintptr_t src = src_start; src < src_end; src += sizeof(uint32_t)) {
427 *(volatile uint32_t*)dst = *(const volatile uint32_t*)src;
428 dst += sizeof(uint32_t);
429 }
430}
431
451static ra8_err_t tz_usb_route_pins(void)
452{
453 /* Establish the pin-validator baseline. The Secure boot never runs
454 * ra8_infrastructure_init (its main() is dead -- BLXNS does not return), so
455 * the validator bitmap is in an uninitialised-contract state and warm
456 * resets leave stale claims (SRAM survives SYSRESETREQ; PFS does not), which
457 * would make the USB-pin claims spuriously conflict. Reset it first. */
459
460 /* Route the USB-FS pins as the DEVICE (Secure owns PFS). P5_00 LOW = dev. */
461 ra8_err_t err = ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_vbus,
463 "tz_usb.fs_vbus");
464 if (err == k_ra8_ok) {
465 err = ra8_gpio_output_init((ra8_port_pin_t)k_tz_usb_pin_vbusen, k_ra8_level_low);
466 }
467 if (err == k_ra8_ok) {
468 err =
469 ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_dp, k_ra8_psel_usb_fs, "tz_usb.fs_dp");
470 }
471 if (err == k_ra8_ok) {
472 err =
473 ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_dm, k_ra8_psel_usb_fs, "tz_usb.fs_dm");
474 }
475
476 /* USBHS host pins: PD07 HIGH (U18 supplies J7 VBUS), route P4_08
477 * USBHS_VBUS. (The host-mode mux is the U15 expander -- handled later.) */
478 if (err == k_ra8_ok) {
479 err = ra8_gpio_output_init((ra8_port_pin_t)k_tz_usb_pin_hs_pwr, k_ra8_level_high);
480 }
481 if (err == k_ra8_ok) {
482 err = ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_hs_vbus,
484 "tz_usb.hs_vbus");
485 }
486
487 /* Enable the USBHS UTMI PLL (Secure CGC; PLL1 already locked). A warm
488 * reset leaves the CGC PLL domain running, so a re-enable reports
489 * k_ra8_err_busy ("already locked"); the clock is up either way, so treat
490 * busy as success. */
491 if (err == k_ra8_ok) {
492 const ra8_err_t pll_err = ra8_cgc_usbhs_pll_enable();
493 if ((pll_err != k_ra8_ok) && (pll_err != k_ra8_err_busy)) {
494 err = pll_err;
495 }
496 }
497 return err;
498}
499
518static void tz_usb_mark_ns(void)
519{
520 /* HUM Ch 51.8.1 "PSARB : Peripheral Security Attribution Register B" p 3284
521 * -- PSARB11 = USBFS0, PSARB12 = USBHS (+ their MSTPCRB.MSTPB11/12 bits);
522 * 0 = Secure, 1 = Non-secure. PSARx share the PRCR_S.PRC4 write gate with
523 * SRAMSABARn (HUM Ch 13.2.1 "Association between PRCR bits and use of
524 * registers" p 521), so the gate must be open across the write; HUM "Security
525 * or Privilege Bit Write Timing" p 3301 then requires reading back until the
526 * value matches. */
527 /* HUM Ch 13.2.1 "PRCR_S" p 521 -- open PRC4. */
528 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_open;
529 const uint32_t want = tz_read32(k_tz_psarb_addr) | (uint32_t)k_tz_psarb_usb_ns;
530 tz_write32(k_tz_psarb_addr, want);
531 uint32_t seen = 0U;
532 for (uint32_t spin = 0U; spin < (uint32_t)k_tz_psarb_readback_spins; spin += 1U) {
533 seen = tz_read32(k_tz_psarb_addr);
534 if (seen == want) {
535 break;
536 }
537 }
538 /* HUM Ch 13.2.1 "PRCR_S" p 521 -- re-lock PRC4. */
539 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_close;
541}
542
571static void tz_usb_handoff_prepare(void)
572{
573 /* 1+2+3. Route USB pins (FS device + HS host) and enable the USBHS PLL. */
574 const ra8_err_t pins_err = tz_usb_route_pins();
575 g_tz_usb_pins_err = (uint32_t)pins_err;
576
577 /* 4. Set the U15 I/O-expander to USBHS host mode (SW4-8 -> Host). Decoupled
578 * from the deterministic setup above and best-effort: on a cold boot the
579 * single I2C write lands (probe -> success); after a warm reset RIIC1's
580 * BBSY can still be set, reporting k_ra8_err_busy. The external PI4IOE
581 * latches its host-mode output, so the USBHS host role persists across the
582 * MCU warm reset -- the self-loop still enumerates (the HIL gate proves
583 * it). A retry cannot help here: the expander claims the SCL1/SDA1 pins on
584 * the first try and a second try would fault the pin validator. */
586 g_tz_usb_expander_err = (uint32_t)exp_err;
587
588 /* 5. Mark BOTH USB controllers Non-secure in PSARB (bits 11 + 12). */
589 tz_usb_mark_ns();
590}
591
592#endif /* RA8_TRUSTZONE_ENABLE */
593
595{
596#ifdef RA8_TRUSTZONE_ENABLE
597 /* 0. Hand USB-FS (pins + PSARB NS attribution) to the NS world. */
598 tz_usb_handoff_prepare();
599
600 /* 1. Carve the SRAM2 NS aperture via the runtime SRAMSABAR boundary. */
601 tz_sram_ns_boundary();
602
603 /* 2. Programme the bit[28] SAU (NSC veneers + IDAU-NS ranges), enable. */
604 if (tz_sau_program() != k_ra8_ok) {
605 return; /* Fall through to the S-side main() fallback. */
606 }
607
608 /* 3. Copy the NS image into the now-Non-secure SRAM alias. */
609 tz_copy_ns_image();
610
611 /* 4. Clear the Secure PRIMASK before handing off. SystemInit masked IRQs
612 * (CPSID i) for secure bring-up; a set PRIMASK_S boosts the execution
613 * priority and masks NON-secure exceptions too, so the NS ThreadX
614 * PendSV / SysTick would never fire. The NS side cannot clear PRIMASK_S
615 * (it is Secure-banked), so do it here, right before BLXNS. */
616 __asm__ volatile("cpsie i" ::: "memory");
617
618 /* 5. BLXNS into the NS reset vector (slot 1 of the NS vector table at the
619 * fixed run base 0x3210_0000). Does not return on hardware. */
620 const ra8_err_t jump_err =
621 ra8_tz_secure_boot_jump_ns((const uint32_t*)(uintptr_t)k_tz_ns_run_base);
622 if (jump_err != k_ra8_ok) {
623 /* Reached on hardware ONLY when the NS image was DENIED (vector-table
624 * validation or the root-of-trust gate failed). Latch the verdict for a
625 * J-Link probe and fall through to the S-side main() fallback -- never
626 * treat the NS world as live. */
627 g_tz_jump_ns_err = (uint32_t)jump_err;
628 return;
629 }
630
631 /* On host (RA8_OFF_TARGET) the library stubs BLXNS and returns
632 * k_ra8_ok; on target this point is unreachable. */
633#endif
634}
void ra8_trustzone_init(void)
Programme + enable the SAU per the partition.
uint32_t g_ra8_ls_sgstubs_start
Veneer-region start (NSC).
uint32_t g_ra8_ls_sgstubs_end
Veneer-region end (NSC).
tz_ns_image_t
Fixed NS-image addresses (two-project build, #96).
@ k_tz_ns_load_base
NS image LMA (Secure MRAM).
@ k_tz_ns_copy_size
Bytes copied LMA->VMA (192 KB).
@ k_tz_ns_run_base
NS image VMA (SRAM2 NS alias).
volatile uint32_t g_tz_usb_pins_err
First non-OK ra8_err_t from the USB pin + PLL setup (0 = OK).
volatile uint32_t g_tz_usb_psarb_readback
Confirmed PSARB read-back after the USBFS NS-attribution write.
volatile uint32_t g_tz_usb_expander_err
Last ra8_err_t from the U15 I/O-expander host-mode write (0 = OK).
volatile uint32_t g_tz_jump_ns_err
Denial verdict from ra8_tz_secure_boot_jump_ns (0 = never denied).
Board-support layer for the Renesas EK-RA8D2 v1 evaluation kit.
ra8_err_t ra8_board_io_expander_set_usbhs_host_mode(void)
Drive the U15 I/O expander to select USB-HS HOST mode.
@ k_ra8_board_usbhs_pin_pwr
PD07 J7 host-power switch (HIGH = U18 drives 5 V VBUS).
@ k_ra8_board_usbhs_pin_vbus
P4_08 USBHS_VBUS sense.
@ k_ra8_board_usbfs_pin_dm
P8_15 D-.
@ k_ra8_board_usbfs_pin_vbusen
P5_00 VBUSEN GPIO.
@ k_ra8_board_usbfs_pin_vbus
P4_07 VBUS sense.
@ k_ra8_board_usbfs_pin_dp
P8_14 D+.
High-level Clock Generation Circuit driver.
ra8_err_t ra8_cgc_usbhs_pll_enable(void)
Bring up the USBHS PHY reference clock + module clock.
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_busy
Resource busy – blocking operation cannot proceed.
Definition ra8_err.h:195
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
PSEL codes for peripheral pin routing on the RA8D2.
@ k_ra8_psel_usb_fs
10011b: USB Full-Speed.
@ k_ra8_psel_usb_hs
10100b: USB High-Speed (e.g.
Runtime Pin-Ownership Validator.
void ra8_pin_validator_reset(void)
Reset the validator (release every pin).
Typed Port / Pin Constants for the RA8D2 IOPORT Module.
ra8_port_pin_t
Packed (port << 8) | pin pin identifier.
@ k_ra8_level_high
Drive or read 1.
@ k_ra8_level_low
Drive or read 0.
High-level GPIO helpers on top of the PORT + PFS register layer.
ra8_err_t ra8_gpio_output_init(ra8_port_pin_t pin, ra8_level_t init_level)
Configure a pin as a digital output and drive it to an initial level.
Definition gpio.c:88
ra8_err_t ra8_pfs_route_peripheral(ra8_port_pin_t pin, ra8_psel_t psel, const char *owner)
Route a pin to a non-IRQ peripheral function via PFS.PSEL.
Definition gpio.c:238
FSP-style TrustZone secure-boot for the Cortex-M85 (CPU0).
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.