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