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