1 /*
2 * Copyright (c) 2018-2023, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7 #ifndef __TFM_ARCH_V8M_H__
8 #define __TFM_ARCH_V8M_H__
9
10 #include <stdint.h>
11 #include <stdbool.h>
12
13 #include "cmsis_compiler.h"
14 #include "tfm_core_trustzone.h"
15 #include "utilities.h"
16 #include "private/assert.h"
17
18 #define EXC_RETURN_RES1 (0x1FFFFUL << 7)
19
20 /* Initial EXC_RETURN value in LR when a thread is loaded at the first time */
21 #define EXC_RETURN_THREAD_PSP \
22 EXC_RETURN_PREFIX | EXC_RETURN_RES1 | \
23 EXC_RETURN_S | EXC_RETURN_DCRS | \
24 EXC_RETURN_FTYPE | EXC_RETURN_MODE | \
25 EXC_RETURN_SPSEL | EXC_RETURN_ES
26
27 #define EXC_RETURN_THREAD_MSP \
28 EXC_RETURN_PREFIX | EXC_RETURN_RES1 | \
29 EXC_RETURN_S | EXC_RETURN_DCRS | \
30 EXC_RETURN_FTYPE | EXC_RETURN_MODE | \
31 EXC_RETURN_ES
32
33 #define EXC_RETURN_HANDLER \
34 EXC_RETURN_PREFIX | EXC_RETURN_RES1 | \
35 EXC_RETURN_S | EXC_RETURN_DCRS | \
36 EXC_RETURN_FTYPE | EXC_RETURN_ES
37
38 /* Exception numbers */
39 #define EXC_NUM_THREAD_MODE (0)
40 #define EXC_NUM_SVCALL (11)
41 #define EXC_NUM_PENDSV (14)
42
43 #define SCB_ICSR_ADDR (0xE000ED04)
44 #define SCB_ICSR_PENDSVSET_BIT (0x10000000)
45
46 /* Disable NS exceptions by setting NS PRIMASK to 1 */
47 #define TFM_NS_EXC_DISABLE() __TZ_set_PRIMASK_NS(1)
48 /* Enable NS exceptions by setting NS PRIMASK to 0 */
49 #define TFM_NS_EXC_ENABLE() __TZ_set_PRIMASK_NS(0)
50
51 extern uint64_t __STACK_SEAL;
52
53 /**
54 * \brief Check whether Secure or Non-secure stack is used to restore stack
55 * frame on exception return.
56 *
57 * \param[in] lr LR register containing the EXC_RETURN value.
58 *
59 * \retval true Secure stack is used to restore stack frame on
60 * exception return.
61 * \retval false Non-secure stack is used to restore stack frame on
62 * exception return.
63 */
is_return_secure_stack(uint32_t lr)64 __STATIC_INLINE bool is_return_secure_stack(uint32_t lr)
65 {
66 return (lr & EXC_RETURN_S) ? true : false;
67 }
68
69 /**
70 * \brief Check whether the default stacking rules apply, or whether the
71 * Additional state context, also known as callee registers,
72 * are already on the stack.
73 * DCRS bit is only present from V8M and above.
74 * If DCRS is 1 then Stack contains:
75 * r0, r1, r2, r3, r12, r14 (lr), the return address and xPSR
76 *
77 * If DCRS is 0 then the stack contains the following too before
78 * the caller-saved registers:
79 * Integrity signature, res, r4, r5, r6, r7, r8, r9, r10, r11
80 *
81 * \param[in] lr LR register containing the EXC_RETURN value.
82 *
83 * \retval true Default rules for stacking the Additional state
84 * context registers followed.
85 * \retval false Stacking of the Additional state context
86 * registers skipped.
87 */
is_default_stacking_rules_apply(uint32_t lr)88 __STATIC_INLINE bool is_default_stacking_rules_apply(uint32_t lr)
89 {
90 return (lr & EXC_RETURN_DCRS) ? true : false;
91 }
92
93 /**
94 * \brief Check whether the stack frame for this exception has space allocated
95 * for Floating Point(FP) state information.
96 *
97 * \param[in] lr LR register containing the EXC_RETURN value.
98 *
99 * \retval true The stack allocates space for FP information
100 * \retval false The stack doesn't allocate space for FP information
101 */
is_stack_alloc_fp_space(uint32_t lr)102 __STATIC_INLINE bool is_stack_alloc_fp_space(uint32_t lr)
103 {
104 return (lr & EXC_RETURN_FTYPE) ? false : true;
105 }
106
107 /**
108 * \brief Get value of PSPLIM register.
109 *
110 * \retval psplim Register value in PSPLIM register.
111 */
tfm_arch_get_psplim(void)112 __STATIC_INLINE uint32_t tfm_arch_get_psplim(void)
113 {
114 return __get_PSPLIM();
115 }
116
117 /**
118 * \brief Set PSPLIM register.
119 *
120 * \param[in] psplim Register value to be written into PSPLIM.
121 */
tfm_arch_set_psplim(uint32_t psplim)122 __STATIC_INLINE void tfm_arch_set_psplim(uint32_t psplim)
123 {
124 __set_PSPLIM(psplim);
125 }
126
127 /**
128 * \brief Set MSP limit value.
129 *
130 * \param[in] msplim MSP limit value to be written.
131 */
tfm_arch_set_msplim(uint32_t msplim)132 __STATIC_INLINE void tfm_arch_set_msplim(uint32_t msplim)
133 {
134 __set_MSPLIM(msplim);
135 }
136
137 /**
138 * \brief Seal the thread stack.
139 *
140 * This function must be called only when the caller is using MSP.
141 *
142 * \param[in] stk Thread stack address.
143 *
144 * \retval stack Updated thread stack address.
145 */
arch_seal_thread_stack(uintptr_t stk)146 __STATIC_INLINE uintptr_t arch_seal_thread_stack(uintptr_t stk)
147 {
148 SPM_ASSERT((stk & 0x7) == 0);
149 stk -= TFM_STACK_SEALED_SIZE;
150
151 *((uint32_t *)stk) = TFM_STACK_SEAL_VALUE;
152 *((uint32_t *)(stk + 4)) = TFM_STACK_SEAL_VALUE;
153
154 return stk;
155 }
156
157 /**
158 * \brief Check MSP sealing.
159 *
160 * Sealing must be done in the Reset_Handler() on a 8 byte region
161 * (__STACK_SEAL) defined in the linker scripts.
162 * (It is a CMSIS recommendation)
163 *
164 */
tfm_arch_check_msp_sealing(void)165 __STATIC_INLINE void tfm_arch_check_msp_sealing(void)
166 {
167 SPM_ASSERT(*(uint64_t *)(&__STACK_SEAL) == __TZ_STACK_SEAL_VALUE);
168 }
169
170 /*
171 * Update thread stack to architecture registers.
172 * The stack 'bottom' is higher address in this architecture,
173 * and 'toplimit' is the limit of top which is lower address.
174 */
arch_update_process_sp(uint32_t bottom,uint32_t toplimit)175 __STATIC_INLINE void arch_update_process_sp(uint32_t bottom,
176 uint32_t toplimit)
177 {
178 __set_PSP(bottom);
179 __set_PSPLIM(toplimit);
180 __ISB();
181 }
182
183 #endif
184