1 /*
2 * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
3 * Copyright (c) 2022 Cypress Semiconductor Corporation (an Infineon
4 * company) or an affiliate of Cypress Semiconductor Corporation. All rights
5 * reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10 #ifndef __TFM_ARCH_H__
11 #define __TFM_ARCH_H__
12
13 /* This header file collects the architecture related operations. */
14
15 #include <stdbool.h>
16 #include <stddef.h>
17 #include <inttypes.h>
18 #include "fih.h"
19 #include "tfm_hal_device_header.h"
20 #include "cmsis_compiler.h"
21
22 #if defined(__ARM_ARCH_8_1M_MAIN__) || \
23 defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8M_BASE__)
24 #include "tfm_arch_v8m.h"
25 #elif defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7M__) || \
26 defined(__ARM_ARCH_7EM__)
27 #include "tfm_arch_v6m_v7m.h"
28 #else
29 #error "Unsupported ARM Architecture."
30 #endif
31
32 #define SCHEDULER_ATTEMPTED 2 /* Schedule attempt when scheduler is locked. */
33 #define SCHEDULER_LOCKED 1
34 #define SCHEDULER_UNLOCKED 0
35
36 #define XPSR_T32 0x01000000
37
38 /* Define IRQ level */
39 #if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__)
40 #define SecureFault_IRQnLVL (0)
41 #define MemoryManagement_IRQnLVL (0)
42 #define BusFault_IRQnLVL (0)
43 #define SVCall_IRQnLVL (0)
44 #elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
45 #define MemoryManagement_IRQnLVL (0)
46 #define BusFault_IRQnLVL (0)
47 #define SVCall_IRQnLVL (0)
48 #elif defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)
49 #define SVCall_IRQnLVL (0)
50 #else
51 #error "Unsupported ARM Architecture."
52 #endif
53
54
55 /* The lowest secure interrupt priority */
56 #ifdef CONFIG_TFM_USE_TRUSTZONE
57 /* IMPORTANT NOTE:
58 *
59 * Although the priority of the secure PendSV must be the lowest possible
60 * among other interrupts in the Secure state, it must be ensured that
61 * PendSV is not preempted nor masked by Non-Secure interrupts to ensure
62 * the integrity of the Secure operation.
63 * When AIRCR.PRIS is set, the Non-Secure execution can act on
64 * FAULTMASK_NS, PRIMASK_NS or BASEPRI_NS register to boost its priority
65 * number up to the value 0x80.
66 * For this reason, set the priority of the PendSV interrupt to the next
67 * priority level configurable on the platform, just below 0x80.
68 */
69 #define PENDSV_PRIO_FOR_SCHED ((1 << (__NVIC_PRIO_BITS - 1)) - 1)
70
71 #if CONFIG_TFM_SECURE_THREAD_MASK_NS_INTERRUPT == 1
72 #if (!defined(__ARM_ARCH_8_1M_MAIN__)) && (!defined(__ARM_ARCH_8M_MAIN__))
73 #error CONFIG_TFM_SECURE_THREAD_MASK_NS_INTERRUPT is not supported in Baseline implementations
74 #endif /* (!defined(__ARM_ARCH_8_1M_MAIN__)) && (!defined(__ARM_ARCH_8M_MAIN__)) */
75 /* IMPORTANT NOTE:
76 *
77 * When AIRCR.PRIS is set, the Non-Secure execution can act on
78 * FAULTMASK_NS, PRIMASK_NS or BASEPRI_NS register to boost its priority
79 * number up to the value 0x80. To mask NS interrupts in secure thread
80 * execution, set the priority of Secure thread mode execution to this value.
81 */
82 #define SECURE_THREAD_EXECUTION_PRIORITY 0x80
83 #endif /* CONFIG_TFM_SECURE_THREAD_MASK_NS_INTERRUPT == 1 */
84 #else /* CONFIG_TFM_USE_TRUSTZONE */
85 /* If TZ is not in use, we have the full priority range available */
86 #define PENDSV_PRIO_FOR_SCHED ((1 << __NVIC_PRIO_BITS) - 1)
87 #endif /* CONFIG_TFM_USE_TRUSTZONE */
88
89 /* State context defined by architecture */
90 struct tfm_state_context_t {
91 uint32_t r0;
92 uint32_t r1;
93 uint32_t r2;
94 uint32_t r3;
95 uint32_t r12;
96 uint32_t lr;
97 uint32_t ra;
98 uint32_t xpsr;
99 };
100
101 /* Context addition to state context */
102 struct tfm_additional_context_t {
103 uint32_t integ_sign; /* Integrity signature */
104 uint32_t reserved; /* Reserved */
105 uint32_t callee[8]; /* R4-R11. NOT ORDERED!! */
106 };
107
108 #if (CONFIG_TFM_FLOAT_ABI >= 1)
109 #if defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__)
110 struct tfm_fpu_context_t {
111 uint32_t s16_s31[16]; /* S16-S31 */
112 };
113 #define TFM_FPU_CONTEXT struct tfm_fpu_context_t
114 #endif /* defined(__ARM_ARCH_8_1M_MAIN__) || defined(__ARM_ARCH_8M_MAIN__) */
115 #endif /* CONFIG_TFM_FLOAT_ABI */
116
117 #ifdef TFM_FPU_CONTEXT
118 #define TFM_FPU_CONTEXT_SIZE sizeof(TFM_FPU_CONTEXT)
119 #else
120 #define TFM_FPU_CONTEXT_SIZE 0
121 #endif
122
123 /* Full thread context */
124 struct full_context_t {
125 struct tfm_additional_context_t addi_ctx;
126 #ifdef TFM_FPU_CONTEXT
127 TFM_FPU_CONTEXT fpu_ctx;
128 #endif
129 struct tfm_state_context_t stat_ctx;
130 };
131
132 /* Context control.
133 * CAUTION: Assembly references this structure. DO CHECK the below functions
134 * before changing the structure:
135 'PendSV_Handler'
136 */
137 struct context_ctrl_t {
138 uint32_t sp; /* Stack pointer (higher address).
139 * THIS MUST BE THE FIRST MEMBER OF
140 * THE STRUCT.
141 */
142 uint32_t exc_ret; /* EXC_RETURN pattern.
143 * THIS MUST BE THE SECOND MEMBER OF
144 * THE STRUCT.
145 */
146 uint32_t sp_limit; /* Stack limit (lower address) */
147 uint32_t sp_base; /* Stack usage start (higher addr) */
148 };
149
150 /*
151 * The context on MSP when de-privileged FLIH Function calls SVC to return.
152 * It is the same when de-privileged FLIH Function is ready to run.
153 */
154 struct context_flih_ret_t {
155 uint64_t stack_seal; /* Two words stack seal */
156 struct tfm_additional_context_t addi_ctx;
157 #ifdef TFM_FPU_CONTEXT
158 TFM_FPU_CONTEXT fpu_ctx;
159 #endif
160 uint32_t exc_return; /* exception return value on SVC_PREPARE_DEPRIV_FLIH */
161 uint32_t dummy; /* dummy value for 8 bytes aligned */
162 uint32_t psp; /* PSP when interrupt exception occurs */
163 uint32_t psplim; /* PSPLIM when interrupt exception occurs when */
164 struct tfm_state_context_t state_ctx; /* ctx on SVC_PREPARE_DEPRIV_FLIH */
165 };
166
167 /* Assign stack and stack limit to the context control instance. */
168 #define ARCH_CTXCTRL_INIT(x, buf, sz) do { \
169 (x)->sp = ((uint32_t)(buf) + (uint32_t)(sz)) & ~0x7; \
170 (x)->sp_limit = ((uint32_t)(buf) + 7) & ~0x7; \
171 (x)->sp_base = (x)->sp; \
172 (x)->exc_ret = 0; \
173 } while (0)
174
175 /* Allocate 'size' bytes in stack. */
176 #define ARCH_CTXCTRL_ALLOCATE_STACK(x, size) \
177 ((x)->sp -= ((size) + 7) & ~0x7)
178
179 /* The last allocated pointer. */
180 #define ARCH_CTXCTRL_ALLOCATED_PTR(x) ((x)->sp)
181
182 /* Prepare an exception return pattern on the stack. */
183 #define ARCH_CTXCTRL_EXCRET_PATTERN(x, param0, param1, param2, param3, pfn, pfnlr) do { \
184 (x)->r0 = (uint32_t)(param0); \
185 (x)->r1 = (uint32_t)(param1); \
186 (x)->r2 = (uint32_t)(param2); \
187 (x)->r3 = (uint32_t)(param3); \
188 (x)->ra = (uint32_t)(pfn); \
189 (x)->lr = (uint32_t)(pfnlr); \
190 (x)->xpsr = XPSR_T32; \
191 } while (0)
192
193 /* Set state context parameter r0. */
194 #define ARCH_STATE_CTX_SET_R0(x, r0_val) \
195 ((x)->r0 = (uint32_t)(r0_val))
196
197 /*
198 * Claim a statically initialized context control instance.
199 * Make the start stack pointer at 'stack_buf[stack_size]' because
200 * the hardware acts in a 'Decrease-then-store' behaviour.
201 */
202 #define ARCH_CLAIM_CTXCTRL_INSTANCE(name, stack_buf, stack_size) \
203 struct context_ctrl_t name = { \
204 .sp = (uint32_t)&stack_buf[stack_size], \
205 .sp_base = (uint32_t)&stack_buf[stack_size], \
206 .sp_limit = (uint32_t)stack_buf, \
207 .exc_ret = 0, \
208 }
209
__save_disable_irq(void)210 __STATIC_INLINE uint32_t __save_disable_irq(void)
211 {
212 uint32_t result;
213
214 __ASM volatile ("mrs %0, primask \n cpsid i" : "=r" (result) :: "memory");
215 return result;
216 }
217
__restore_irq(uint32_t status)218 __STATIC_INLINE void __restore_irq(uint32_t status)
219 {
220 __ASM volatile ("msr primask, %0" :: "r" (status) : "memory");
221 }
222
223 __attribute__ ((always_inline))
__get_active_exc_num(void)224 __STATIC_INLINE uint32_t __get_active_exc_num(void)
225 {
226 IPSR_Type IPSR;
227
228 /* if non-zero, exception is active. NOT banked S/NS */
229 IPSR.w = __get_IPSR();
230 return IPSR.b.ISR;
231 }
232
233 __attribute__ ((always_inline))
__set_CONTROL_nPRIV(uint32_t nPRIV)234 __STATIC_INLINE void __set_CONTROL_nPRIV(uint32_t nPRIV)
235 {
236 CONTROL_Type ctrl;
237
238 ctrl.w = __get_CONTROL();
239 ctrl.b.nPRIV = nPRIV;
240 __set_CONTROL(ctrl.w);
241 __ISB();
242 }
243
244 /**
245 * \brief Whether in privileged level
246 *
247 * \retval true If current execution runs in privileged level.
248 * \retval false If current execution runs in unprivileged level.
249 */
tfm_arch_is_priv(void)250 __STATIC_INLINE bool tfm_arch_is_priv(void)
251 {
252 CONTROL_Type ctrl;
253
254 /* If in Handler mode */
255 if (__get_IPSR()) {
256 return true;
257 }
258
259 /* If in privileged Thread mode */
260 ctrl.w = __get_CONTROL();
261 if (!ctrl.b.nPRIV) {
262 return true;
263 }
264
265 return false;
266 }
267
268 #if (CONFIG_TFM_FLOAT_ABI >= 1) && CONFIG_TFM_LAZY_STACKING
269 #define ARCH_FLUSH_FP_CONTEXT() __asm volatile("vmov.f32 s0, s0 \n":::"memory")
270 #else
271 #define ARCH_FLUSH_FP_CONTEXT()
272 #endif
273
274 /* Set secure exceptions priority. */
275 void tfm_arch_set_secure_exception_priorities(void);
276
277 #ifdef TFM_FIH_PROFILE_ON
278 /* Check secure exception priority */
279 FIH_RET_TYPE(int32_t) tfm_arch_verify_secure_exception_priorities(void);
280 #endif
281
282 /* Configure various extensions. */
283 void tfm_arch_config_extensions(void);
284
285 #if (CONFIG_TFM_FLOAT_ABI > 0)
286 /* Clear float point data. */
287 void tfm_arch_clear_fp_data(void);
288 #endif
289
290 /*
291 * This function is called after SPM has initialized.
292 * It frees the stack used by SPM initialization and do Exception Return.
293 * It does not return.
294 */
295 void tfm_arch_free_msp_and_exc_ret(uint32_t msp_base, uint32_t exc_return);
296
297 /*
298 * This function sets return value on APIs that cause scheduling, for example
299 * psa_wait(), by manipulating the control context - this is usaully setting the
300 * R0 register of the thread context.
301 */
302 void tfm_arch_set_context_ret_code(const struct context_ctrl_t *p_ctx_ctrl, uint32_t ret_code);
303
304 /* Init a thread context on thread stack and update the control context. */
305 void tfm_arch_init_context(struct context_ctrl_t *p_ctx_ctrl,
306 uintptr_t pfn, void *param, uintptr_t pfnlr);
307
308 /*
309 * Refresh the HW (sp, splimit) according to the given control context and
310 * returns the EXC_RETURN payload (caller might need it for following codes).
311 *
312 * The p_ctx_ctrl must have been initialized by 'tfm_arch_init_context'.
313 */
314 uint32_t tfm_arch_refresh_hardware_context(const struct context_ctrl_t *p_ctx_ctrl);
315
316 /*
317 * Lock the scheduler. Any scheduling attempt during locked period will not
318 * take place and is recorded.
319 */
320 void arch_acquire_sched_lock(void);
321
322 /*
323 * Release the scheduler lock and return if there are scheduling attempts during
324 * locked period. The recorded attempts are cleared after this function so do
325 * not call it a second time after unlock to query attempt status.
326 *
327 * return value:
328 * SCHEDULER_ATTEMPTED: unlocked successfully but there are recorded attempts
329 * or function get called without locked.
330 * other values: unlocked successfully without attempts detected.
331 */
332 uint32_t arch_release_sched_lock(void);
333
334 /*
335 * Try to schedule if scheduler is not locked, otherwise record the schedule
336 * attempt and return without scheduling.
337 */
338 uint32_t arch_attempt_schedule(void);
339
340 /*
341 * Thread Function Call at Thread mode. It is called in the IPC backend and
342 * isolation level 1. The function switches to the SPM stack to execute the
343 * target PSA API to avoid using up the Secure Partitions' stacks. The NS agent
344 * shares the stack with the SPM so it doesn't need to switch.
345 *
346 * The stack check process destroys the caller registers so the input args and
347 * the target PSA API address are stored in the caller stack at the beginning.
348 * They are loaded again before the PSA API is called. This function is
349 * non-preemptive except for the target PSA API execution.
350 *
351 * NOTE: This function cannot be called by any C functions as it uses a
352 * customized parameter passing method and puts the target function address in
353 * r12. These input parameters a0~a3 come from standard PSA interface input.
354 * The return value is stored in r0 for the PSA API to return.
355 */
356 void tfm_arch_thread_fn_call(uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3);
357
358 /*
359 * Reset MSP to msp_base.
360 * Use PSP as the current stack in Thread mode.
361 * Execute two init functions in turn.
362 */
363 void arch_clean_stack_and_launch(void *param, uintptr_t spm_init_func,
364 uintptr_t ns_agent_entry, uint32_t msp_base);
365
366 #endif
367