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