1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
4 *
5 */
6
7 #include "tfm_hal_multi_core.h"
8 #include "platform_multicore.h"
9 #include "target_cfg.h"
10 #include "region_defs.h"
11
12 #include "interrupt.h"
13 #include "pico/multicore.h"
14 #include "hardware/structs/sio.h"
15
16 /* Entrypoint function declaration */
17 extern void ns_agent_tz_main(uint32_t c_entry);
18
19 volatile uint32_t CORE1_RUNNING;
20
multicore_ns_fifo_rvalid(void)21 bool multicore_ns_fifo_rvalid(void) {
22 return !!(sio_ns_hw->fifo_st & SIO_FIFO_ST_VLD_BITS);
23 }
24
multicore_ns_fifo_wready(void)25 bool multicore_ns_fifo_wready(void) {
26 return !!(sio_ns_hw->fifo_st & SIO_FIFO_ST_RDY_BITS);
27 }
28
multicore_ns_fifo_push_blocking_inline(uint32_t data)29 void multicore_ns_fifo_push_blocking_inline(uint32_t data) {
30 /* We wait for the fifo to have some space */
31 while (!multicore_ns_fifo_wready())
32 tight_loop_contents();
33
34 sio_ns_hw->fifo_wr = data;
35
36 /* Fire off an event to the other core */
37 __sev();
38 }
39
multicore_ns_fifo_pop_blocking_inline(void)40 uint32_t multicore_ns_fifo_pop_blocking_inline(void) {
41 /* If nothing there yet, we wait for an event first,
42 to try and avoid too much busy waiting */
43 while (!multicore_ns_fifo_rvalid())
44 __wfe();
45
46 return sio_ns_hw->fifo_rd;
47 }
48
wait_for_core1_ready(void)49 static void wait_for_core1_ready(void)
50 {
51 uint32_t stage;
52 while (1) {
53 stage = multicore_fifo_pop_blocking();
54 if (stage == CORE1_S_READY) {
55 break;
56 }
57 }
58 }
59
60 /* If Core0 wants to write Flash, Core1 must not use it.
61 * As Core1 partly runs from Flash, it must be stopped while Core0 is writing.
62 * The simplest solution is for Core0 to ring Core1's doorbell where we wait out
63 * the flash operation, using spinlock. */
__not_in_flash_func(Core1Doorbell_Handler)64 static void __not_in_flash_func(Core1Doorbell_Handler)() {
65 uint32_t status = 0;
66 /* Prevent IRQs to fire, as their handlers might be in Flash */
67 __ASM volatile ("mrs %0, primask \n cpsid i" : "=r" (status) :: "memory");
68 /* Check if this is the "flash-in-use" doorbell */
69 if (sio_hw->doorbell_in_set & FLASH_DOORBELL_MASK)
70 {
71 /* Clear doorbell */
72 sio_hw->doorbell_in_clr = FLASH_DOORBELL_MASK;
73 /* Wait for Flash to be available, then release it immediately */
74 while(!*FLASH_SPINLOCK);
75 *FLASH_SPINLOCK = 0x1;
76 /* Check if this is the "halt" doorbell */
77 } else if (sio_hw->doorbell_in_set & HALT_DOORBELL_MASK)
78 {
79 /* Clear doorbell */
80 sio_hw->doorbell_in_clr = HALT_DOORBELL_MASK;
81 while (1) {
82 __WFE();
83 }
84 }
85 /* Restore IRQ status */
86 __ASM volatile ("msr primask, %0" :: "r" (status) : "memory");
87 }
88
core1_entry(void)89 static void core1_entry(void)
90 {
91 __TZ_set_STACKSEAL_S((uint32_t *)__get_MSP());
92 /* Set up isolation boundaries between SPE and NSPE */
93 sau_and_idau_cfg();
94
95 NVIC_SetVector(SIO_IRQ_BELL_IRQn, (uint32_t) Core1Doorbell_Handler);
96 /* Set it to highest priority */
97 NVIC_SetPriority(SIO_IRQ_BELL_IRQn, 0x0);
98 NVIC_EnableIRQ(SIO_IRQ_BELL_IRQn);
99 __enable_irq();
100
101 NVIC_SetTargetState(SIO_IRQ_FIFO_NS_IRQn);
102 multicore_fifo_push_blocking(CORE1_S_READY);
103
104 ns_agent_tz_main(NS_CODE_CORE1_START);
105 }
106
boot_s_core(void)107 static void boot_s_core(void)
108 {
109 CORE1_RUNNING = 0x1;
110 multicore_launch_core1(core1_entry);
111 wait_for_core1_ready();
112 }
113
tfm_hal_boot_ns_cpu(uintptr_t start_addr)114 void tfm_hal_boot_ns_cpu(uintptr_t start_addr)
115 {
116 boot_s_core();
117 return;
118 }
119
tfm_hal_wait_for_ns_cpu_ready(void)120 void tfm_hal_wait_for_ns_cpu_ready(void)
121 {
122 uint32_t stage;
123 while (1) {
124 stage = multicore_ns_fifo_pop_blocking_inline();
125 if (stage == CORE1_NS_READY) {
126 break;
127 }
128 }
129 return;
130 }
131
tfm_hal_get_secure_access_attr(const void * p,size_t s,struct mem_attr_info_t * p_attr)132 void tfm_hal_get_secure_access_attr(const void *p, size_t s,
133 struct mem_attr_info_t *p_attr)
134 {
135 /* Check static memory layout to get memory attributes */
136 tfm_get_secure_mem_region_attr(p, s, p_attr);
137 #if TFM_ISOLATION_LEVEL >= 2
138 p_attr->is_mpu_enabled = true;
139 #endif
140 }
141
tfm_hal_get_ns_access_attr(const void * p,size_t s,struct mem_attr_info_t * p_attr)142 void tfm_hal_get_ns_access_attr(const void *p, size_t s,
143 struct mem_attr_info_t *p_attr)
144 {
145 /* Check static memory layout to get memory attributes */
146 tfm_get_ns_mem_region_attr(p, s, p_attr);
147 }
148