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#ifdef RA8_EREADER_NS_XIP
89 k_tz_ns_run_base = 0x90000000U,
90#else
91 k_tz_ns_run_base = 0x32100000U,
92#endif
93 k_tz_ns_copy_size = 0x00030000U,
95
96#ifdef RA8_TRUSTZONE_ENABLE
97
109typedef enum : uintptr_t {
110 k_tz_sau_ctrl_addr = 0xE000EDD0U,
111 k_tz_sau_type_addr = 0xE000EDD4U,
112 k_tz_sau_rnr_addr = 0xE000EDD8U,
113 k_tz_sau_rbar_addr = 0xE000EDDCU,
114 k_tz_sau_rlar_addr = 0xE000EDE0U,
115 k_tz_sramsabar0_addr = 0x40008400U,
116 k_tz_prcr_s_addr = 0x4001E3FAU,
117 k_tz_psarb_addr = 0x40204004U,
118} tz_reg_addr_t;
119
127typedef enum : uint32_t {
128 k_tz_sau_ctrl_enable = 0x00000001U,
129 k_tz_sau_rlar_enable = 0x00000001U,
130 k_tz_sau_rlar_nsc = 0x00000002U,
131 k_tz_sau_limit_mask = 0xFFFFFFE0U,
132 k_tz_sau_type_mask = 0x000000FFU,
133 k_tz_psarb_usbfs_ns = 0x00000800U,
134 k_tz_psarb_usbhs_ns = 0x00001000U,
135 k_tz_psarb_usb_ns = 0x00001800U,
136 k_tz_psarb_readback_spins = 1000U,
137} tz_field_t;
138
151typedef enum : uint16_t {
152 k_tz_usb_pin_vbus = ((uint16_t)k_ra8_port_4 << 8) | (uint16_t)k_ra8_pin_7,
153 k_tz_usb_pin_vbusen =
154 ((uint16_t)k_ra8_port_5 << 8) | (uint16_t)k_ra8_pin_0,
155 k_tz_usb_pin_dp = ((uint16_t)k_ra8_port_8 << 8) | (uint16_t)k_ra8_pin_14,
156 k_tz_usb_pin_dm = ((uint16_t)k_ra8_port_8 << 8) | (uint16_t)k_ra8_pin_15,
158 k_tz_usb_pin_hs_vbus = ((uint16_t)k_ra8_port_4 << 8) | (uint16_t)k_ra8_pin_8,
159 k_tz_usb_pin_hs_pwr = ((uint16_t)k_ra8_port_13 << 8) | (uint16_t)k_ra8_pin_7,
160} tz_usb_pin_t;
161
172volatile uint32_t g_tz_usb_psarb_readback;
173
182volatile uint32_t g_tz_usb_pins_err;
183
196volatile uint32_t g_tz_usb_expander_err;
197
211volatile uint32_t g_tz_jump_ns_err;
212
219typedef enum : uint16_t {
220 k_tz_prcr_s_open = 0xA510U,
221 k_tz_prcr_s_close = 0xA500U,
222} tz_prcr_t;
223
234typedef enum : uint32_t {
235 k_tz_sau_min_regions = 4U,
236 k_tz_ns_code_base = 0x10000000U,
237 k_tz_ns_code_limit = 0x1FFFFFE0U,
238 k_tz_ns_sram_base = 0x30000000U,
239 k_tz_ns_sram_limit = 0x3FFFFFE0U,
240 k_tz_ns_per_base = 0x50000000U,
241 k_tz_ns_per_limit = 0xDFFFFFE0U,
242 k_tz_sramsabar0_val = 0x00080000U,
243 k_tz_sramsabar1_val = 0x00100000U,
244 k_tz_sramsabar2_val = 0x00100000U,
245 k_tz_sramsabar3_val = 0x001A0000U,
246} tz_partition_t;
247
251typedef enum : uint8_t {
252 k_tz_region_nsc = 0U,
253 k_tz_region_ns_code = 1U,
254 k_tz_region_ns_sram = 2U,
255 k_tz_region_ns_per = 3U,
256} tz_region_t;
257
273static inline void tz_write32(uintptr_t addr, uint32_t value)
274{
275 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 -- generic
276 * secure-MMIO store; SAU / CPSCU callers cite their own page below. */
277 *(volatile uint32_t*)addr = value;
278}
279
296static inline uint32_t tz_read32(uintptr_t addr)
297{
298 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 */
299 return *(volatile uint32_t*)addr;
300}
301
318static void tz_sau_set_region(uint8_t region, uint32_t base, uint32_t limit, bool is_nsc)
319{
320 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 */
321 tz_write32(k_tz_sau_rnr_addr, (uint32_t)region);
322 tz_write32(k_tz_sau_rbar_addr, base & (uint32_t)k_tz_sau_limit_mask);
323 uint32_t rlar = (limit & (uint32_t)k_tz_sau_limit_mask) | (uint32_t)k_tz_sau_rlar_enable;
324 if (is_nsc) {
325 rlar |= (uint32_t)k_tz_sau_rlar_nsc;
326 }
327 tz_write32(k_tz_sau_rlar_addr, rlar);
328}
329
346static void tz_sram_ns_boundary(void)
347{
348 /* Open PRC4 so the CPSCU SRAMSABAR writes below land. */
349 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
350 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_open;
351
352 /* HUM Ch 58.2 "SRAMSABARn : SRAM Security Attribute Boundary Address
353 * Register" p 3527 -- boundary = start address of the NS region; below
354 * = Secure, at/above = Non-secure. */
355 tz_write32(k_tz_sramsabar0_addr + (0U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar0_val);
356 tz_write32(k_tz_sramsabar0_addr + (1U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar1_val);
357 tz_write32(k_tz_sramsabar0_addr + (2U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar2_val);
358 tz_write32(k_tz_sramsabar0_addr + (3U * sizeof(uint32_t)), (uint32_t)k_tz_sramsabar3_val);
359
360 /* Re-lock PRC4 (restore CPSCU write-protect). */
361 /* HUM Ch 13.2.1 "PRCR_S" p 521 */
362 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_close;
363}
364
384static ra8_err_t tz_sau_program(void)
385{
386 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 -- need at
387 * least 4 implemented regions for this layout. */
388 const uint32_t sau_type = tz_read32(k_tz_sau_type_addr);
389 if ((sau_type & (uint32_t)k_tz_sau_type_mask) < (uint32_t)k_tz_sau_min_regions) {
391 }
392
393 /* RLAR limit is the LAST byte of the veneer block (end - 1); the helper
394 * masks it to the 32-byte SAU region quantum. */
395 const uint32_t nsc_base = (uint32_t)(uintptr_t)&g_ra8_ls_sgstubs_start;
396 const uint32_t nsc_limit = (uint32_t)(uintptr_t)&g_ra8_ls_sgstubs_end - 1U;
397 tz_sau_set_region((uint8_t)k_tz_region_nsc, nsc_base, nsc_limit, /*is_nsc=*/true);
398 tz_sau_set_region((uint8_t)k_tz_region_ns_code,
399 (uint32_t)k_tz_ns_code_base,
400 (uint32_t)k_tz_ns_code_limit,
401 /*is_nsc=*/false);
402 tz_sau_set_region((uint8_t)k_tz_region_ns_sram,
403 (uint32_t)k_tz_ns_sram_base,
404 (uint32_t)k_tz_ns_sram_limit,
405 /*is_nsc=*/false);
406 tz_sau_set_region((uint8_t)k_tz_region_ns_per,
407 (uint32_t)k_tz_ns_per_base,
408 (uint32_t)k_tz_ns_per_limit,
409 /*is_nsc=*/false);
410
411 __asm__ volatile("dsb 0xF" ::: "memory");
412 /* Enable the SAU with ALLNS = 0 (default-deny). */
413 /* HUM Ch 51.3.3.3 "Secure Attribution Unit (SAU)" p 3266 */
414 tz_write32(k_tz_sau_ctrl_addr, (uint32_t)k_tz_sau_ctrl_enable);
415 __asm__ volatile("dsb 0xF" ::: "memory");
416 __asm__ volatile("isb" ::: "memory");
417 return k_ra8_ok;
418}
419
420/* The NS image copy exists only for the SRAM-run configuration. Under
421 * RA8_EREADER_NS_XIP the NS .text/.rodata execute in place from the OSPI NS
422 * alias, ra8_trustzone_init() takes the #ifdef arm that does no copy, and this
423 * routine has no call site at all -- so it is compiled out rather than defined
424 * and excused. An unreferenced static is exactly what -Wunused-function is for,
425 * and this file is built with -Werror. */
426#ifndef RA8_EREADER_NS_XIP
444static void tz_copy_ns_image(void)
445{
446 /* Driven through tz_read32 / tz_write32 rather than open-coded casts: those
447 * two are the unit's only integer-to-pointer conversions, and both are
448 * `static inline`, so the emitted loop is the same word copy. */
449 const uintptr_t load_base = (uintptr_t)k_tz_ns_load_base;
450 const uintptr_t run_base = (uintptr_t)k_tz_ns_run_base;
451 for (uintptr_t off = 0U; off < (uintptr_t)k_tz_ns_copy_size; off += sizeof(uint32_t)) {
452 tz_write32(run_base + off, tz_read32(load_base + off));
453 }
454}
455#endif /* !RA8_EREADER_NS_XIP */
456
476static ra8_err_t tz_usb_route_pins(void)
477{
478 /* Establish the pin-validator baseline. The Secure boot never runs
479 * ra8_infrastructure_init (its main() is dead -- BLXNS does not return), so
480 * the validator bitmap is in an uninitialised-contract state and warm
481 * resets leave stale claims (SRAM survives SYSRESETREQ; PFS does not), which
482 * would make the USB-pin claims spuriously conflict. Reset it first. */
484
485 /* Route the USB-FS pins as the DEVICE (Secure owns PFS). P5_00 LOW = dev. */
486 ra8_err_t err = ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_vbus,
488 "tz_usb.fs_vbus");
489 if (err == k_ra8_ok) {
490 err = ra8_gpio_output_init((ra8_port_pin_t)k_tz_usb_pin_vbusen, k_ra8_level_low);
491 }
492 if (err == k_ra8_ok) {
493 err =
494 ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_dp, k_ra8_psel_usb_fs, "tz_usb.fs_dp");
495 }
496 if (err == k_ra8_ok) {
497 err =
498 ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_dm, k_ra8_psel_usb_fs, "tz_usb.fs_dm");
499 }
500
501 /* USBHS host pins: PD07 HIGH (U18 supplies J7 VBUS), route P4_08
502 * USBHS_VBUS. (The host-mode mux is the U15 expander -- handled later.) */
503 if (err == k_ra8_ok) {
504 err = ra8_gpio_output_init((ra8_port_pin_t)k_tz_usb_pin_hs_pwr, k_ra8_level_high);
505 }
506 if (err == k_ra8_ok) {
507 err = ra8_pfs_route_peripheral((ra8_port_pin_t)k_tz_usb_pin_hs_vbus,
509 "tz_usb.hs_vbus");
510 }
511
512 /* Enable the USBHS UTMI PLL (Secure CGC; PLL1 already locked). A warm
513 * reset leaves the CGC PLL domain running, so a re-enable reports
514 * k_ra8_err_busy ("already locked"); the clock is up either way, so treat
515 * busy as success. */
516 if (err == k_ra8_ok) {
517 const ra8_err_t pll_err = ra8_cgc_usbhs_pll_enable();
518 if ((pll_err != k_ra8_ok) && (pll_err != k_ra8_err_busy)) {
519 err = pll_err;
520 }
521 }
522 return err;
523}
524
543static void tz_usb_mark_ns(void)
544{
545 /* HUM Ch 51.8.1 "PSARB : Peripheral Security Attribution Register B" p 3284
546 * -- PSARB11 = USBFS0, PSARB12 = USBHS (+ their MSTPCRB.MSTPB11/12 bits);
547 * 0 = Secure, 1 = Non-secure. PSARx share the PRCR_S.PRC4 write gate with
548 * SRAMSABARn (HUM Ch 13.2.1 "Association between PRCR bits and use of
549 * registers" p 521), so the gate must be open across the write; HUM "Security
550 * or Privilege Bit Write Timing" p 3301 then requires reading back until the
551 * value matches. */
552 /* Open PRC4. HUM Ch 13.2.1 "PRCR_S" p 521 */
553 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_open;
554 const uint32_t want = tz_read32(k_tz_psarb_addr) | (uint32_t)k_tz_psarb_usb_ns;
555 tz_write32(k_tz_psarb_addr, want);
556 uint32_t seen = 0U;
557 for (uint32_t spin = 0U; spin < (uint32_t)k_tz_psarb_readback_spins; spin += 1U) {
558 seen = tz_read32(k_tz_psarb_addr);
559 if (seen == want) {
560 break;
561 }
562 }
563 /* Re-lock PRC4. HUM Ch 13.2.1 "PRCR_S" p 521 */
564 *(volatile uint16_t*)k_tz_prcr_s_addr = (uint16_t)k_tz_prcr_s_close;
566}
567
588static void tz_usb_handoff_prepare(void)
589{
590 /* 1+2+3. Route USB pins (FS device + HS host) and enable the USBHS PLL. */
591 const ra8_err_t pins_err = tz_usb_route_pins();
592 g_tz_usb_pins_err = (uint32_t)pins_err;
593
594 /* 4. Set the U15 I/O-expander to USBHS host mode (SW4-8 -> Host). Decoupled
595 * from the deterministic setup above and best-effort: on a cold boot the
596 * single I2C write lands (probe -> success); after a warm reset RIIC1's
597 * BBSY can still be set, reporting k_ra8_err_busy. The external PI4IOE
598 * latches its host-mode output, so the USBHS host role persists across the
599 * MCU warm reset -- the self-loop still enumerates (the HIL gate proves
600 * it). A retry cannot help here: the expander claims the SCL1/SDA1 pins on
601 * the first try and a second try would fault the pin validator. */
603 g_tz_usb_expander_err = (uint32_t)exp_err;
604
605 /* 5. Mark BOTH USB controllers Non-secure in PSARB (bits 11 + 12). */
606 tz_usb_mark_ns();
607}
608
609#endif /* RA8_TRUSTZONE_ENABLE */
610
612{
613#ifdef RA8_TRUSTZONE_ENABLE
614 /* 0. Hand USB-FS (pins + PSARB NS attribution) to the NS world. */
615 tz_usb_handoff_prepare();
616
617 /* 1. Carve the SRAM2 NS aperture via the runtime SRAMSABAR boundary. */
618 tz_sram_ns_boundary();
619
620 /* 2. Programme the bit[28] SAU (NSC veneers + IDAU-NS ranges), enable. */
621 if (tz_sau_program() != k_ra8_ok) {
622 return; /* Fall through to the S-side main() fallback. */
623 }
624
625#ifdef RA8_EREADER_NS_XIP
626 /* 3. XIP: no image copy. .text/.rodata execute in place from the OSPI NS
627 * alias (0x9000_0000); ns_reset_handler copies only .data into SRAM.
628 * ra8_emulator maps the OSPI window unconditionally, so the fake proof needs
629 * no controller arming here.
630 * TODO(OSPI XIP arming on silicon): before this BLXNS, call
631 * ra8_xspi_xip_enter(instance, enter_code, exit_code) with the EK-RA8D2
632 * OSPI flash's real XIP enter/exit opcodes so the 0x8000_0000/0x9000_0000
633 * window returns flash on hardware, and add a SAU region marking the OSPI
634 * NS alias Non-secure (the IDAU bit[28] alias alone is overridden Secure by
635 * the default SAU). Both are unnecessary in ra8_emulator. */
636#else
637 /* 3. Copy the NS image into the now-Non-secure SRAM alias. */
638 tz_copy_ns_image();
639#endif
640
641 /* 4. Clear the Secure PRIMASK before handing off. SystemInit masked IRQs
642 * (CPSID i) for secure bring-up; a set PRIMASK_S boosts the execution
643 * priority and masks NON-secure exceptions too, so the NS ThreadX
644 * PendSV / SysTick would never fire. The NS side cannot clear PRIMASK_S
645 * (it is Secure-banked), so do it here, right before BLXNS. */
646 __asm__ volatile("cpsie i" ::: "memory");
647
648 /* 5. BLXNS into the NS reset vector (slot 1 of the NS vector table at the
649 * fixed run base 0x3210_0000). Does not return on hardware. */
650 const ra8_err_t jump_err =
651 ra8_tz_secure_boot_jump_ns((const uint32_t*)(uintptr_t)k_tz_ns_run_base);
652 if (jump_err != k_ra8_ok) {
653 /* Reached on hardware ONLY when the NS image was DENIED (vector-table
654 * validation or the root-of-trust gate failed). Latch the verdict for a
655 * J-Link probe and fall through to the S-side main() fallback -- never
656 * treat the NS world as live. */
657 g_tz_jump_ns_err = (uint32_t)jump_err;
658 return;
659 }
660
661 /* On host (RA8_OFF_TARGET) the library stubs BLXNS and returns
662 * k_ra8_ok; on target this point is unreachable. */
663#endif
664}
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.
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_port_13
RA8 port 13.
@ k_ra8_port_4
RA8 port 4.
@ k_ra8_port_5
RA8 port 5.
@ k_ra8_port_8
RA8 port 8.
@ k_ra8_level_high
Drive or read 1.
@ k_ra8_level_low
Drive or read 0.
@ k_ra8_pin_7
RA8 pin 7.
@ k_ra8_pin_14
RA8 pin 14.
@ k_ra8_pin_8
RA8 pin 8.
@ k_ra8_pin_0
RA8 pin 0.
@ k_ra8_pin_15
RA8 pin 15.
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.