1 /*
2 * SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <string.h>
9 #include <stdint.h>
10 #include "aapcs_local.h"
11 #include "config_spm.h"
12 #include "interrupt.h"
13 #include "internal_status_code.h"
14 #include "memory_symbols.h"
15 #include "spm.h"
16 #include "svc_num.h"
17 #include "tfm_arch.h"
18 #include "tfm_svcalls.h"
19 #include "tfm_boot_data.h"
20 #include "tfm_hal_platform.h"
21 #include "tfm_hal_isolation.h"
22 #include "tfm_hal_spm_logdev.h"
23 #include "tfm_core_trustzone.h"
24 #include "utilities.h"
25 #include "ffm/backend.h"
26 #include "ffm/psa_api.h"
27 #include "load/spm_load_api.h"
28 #include "load/partition_defs.h"
29 #include "psa/client.h"
30
31 #define INVALID_PSP_VALUE 0xFFFFFFFFU
32
33 #ifdef PLATFORM_SVC_HANDLERS
34 extern int32_t platform_svc_handlers(uint8_t svc_number,
35 uint32_t *ctx, uint32_t lr);
36 #endif
37
38 #if TFM_ISOLATION_LEVEL > 1
39
40 /*
41 * TODO: To be updated after secure context management is going to implemented.
42 * The variables are used to save PSP, PSPLimit and the EXC_RETURN payload because
43 * they will be changed when preparing to Thread mode to run the PSA API functions.
44 * Later they will be restored when returning from the functions.
45 */
46 static uint32_t saved_psp = INVALID_PSP_VALUE;
47 static uint32_t saved_psp_limit;
48 static uint32_t saved_exc_return;
49
50 typedef psa_status_t (*psa_api_svc_func_t)(uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3);
51
52 /* The order of the functions must match the SVC number index defined in svc_num.h */
53 static const psa_api_svc_func_t psa_api_svc_func_table[] = {
54 /* Client APIs */
55 (psa_api_svc_func_t)tfm_spm_client_psa_framework_version,
56 (psa_api_svc_func_t)tfm_spm_client_psa_version,
57 (psa_api_svc_func_t)tfm_spm_client_psa_call,
58 (psa_api_svc_func_t)tfm_spm_client_psa_connect,
59 (psa_api_svc_func_t)tfm_spm_client_psa_close,
60 /* Secure Partition APIs */
61 (psa_api_svc_func_t)tfm_spm_partition_psa_wait,
62 (psa_api_svc_func_t)tfm_spm_partition_psa_get,
63 (psa_api_svc_func_t)tfm_spm_partition_psa_set_rhandle,
64 (psa_api_svc_func_t)tfm_spm_partition_psa_read,
65 (psa_api_svc_func_t)tfm_spm_partition_psa_skip,
66 (psa_api_svc_func_t)tfm_spm_partition_psa_write,
67 (psa_api_svc_func_t)tfm_spm_partition_psa_reply,
68 (psa_api_svc_func_t)tfm_spm_partition_psa_notify,
69 (psa_api_svc_func_t)tfm_spm_partition_psa_clear,
70 (psa_api_svc_func_t)tfm_spm_partition_psa_eoi,
71 (psa_api_svc_func_t)tfm_spm_partition_psa_panic,
72 (psa_api_svc_func_t)tfm_spm_get_lifecycle_state,
73 (psa_api_svc_func_t)tfm_spm_partition_psa_irq_enable,
74 (psa_api_svc_func_t)tfm_spm_partition_psa_irq_disable,
75 (psa_api_svc_func_t)tfm_spm_partition_psa_reset_signal,
76 (psa_api_svc_func_t)tfm_spm_agent_psa_call,
77 (psa_api_svc_func_t)tfm_spm_agent_psa_connect,
78 (psa_api_svc_func_t)tfm_spm_agent_psa_close,
79 };
80
thread_mode_spm_return(uint32_t result)81 static uint32_t thread_mode_spm_return(uint32_t result)
82 {
83 fih_int fih_rc = FIH_FAILURE;
84 FIH_RET_TYPE(bool) fih_bool;
85 const struct partition_t *p_part_next = GET_CURRENT_COMPONENT();
86 struct tfm_state_context_t *p_tctx = (struct tfm_state_context_t *)saved_psp;
87
88 FIH_CALL(tfm_hal_boundary_need_switch, fih_bool, get_spm_boundary(), p_part_next->boundary);
89 if (fih_not_eq(fih_bool, fih_int_encode(false))) {
90 FIH_CALL(tfm_hal_activate_boundary, fih_rc,
91 p_part_next->p_ldinf, p_part_next->boundary);
92 if (fih_not_eq(fih_rc, fih_int_encode(TFM_HAL_SUCCESS))) {
93 tfm_core_panic();
94 }
95 }
96
97 backend_abi_leaving_spm(result);
98
99 ARCH_STATE_CTX_SET_R0(p_tctx, result);
100
101 tfm_arch_set_psplim(saved_psp_limit);
102 __set_PSP(saved_psp);
103
104 /* Invalidate saved_psp */
105 saved_psp = INVALID_PSP_VALUE;
106
107 return saved_exc_return;
108 }
109
init_spm_func_context(psa_api_svc_func_t svc_func,uint32_t * ctx)110 static void init_spm_func_context(psa_api_svc_func_t svc_func, uint32_t *ctx)
111 {
112 AAPCS_DUAL_U32_T sp_info;
113 struct tfm_state_context_t *p_statctx;
114 uint32_t sp = __get_PSP();
115 uint32_t sp_limit = tfm_arch_get_psplim();
116 const uint32_t stack_alloc_size = (sizeof(*p_statctx) + 7UL) & ~0x7UL;
117
118 saved_psp = sp;
119 saved_psp_limit = sp_limit;
120
121 sp_info.u64_val = backend_abi_entering_spm();
122 /* SPM SP is saved in R0 */
123 if (sp_info.u32_regs.r0 != 0) {
124 sp = sp_info.u32_regs.r0;
125 sp_limit = sp_info.u32_regs.r1;
126 }
127
128 /* Check if there is enough space on stack. */
129 if ((sp_limit + stack_alloc_size) > sp) {
130 tfm_core_panic();
131 }
132
133 /* Allocate memory for p_statctx on the stack. */
134 sp -= stack_alloc_size;
135
136 p_statctx = (struct tfm_state_context_t *)sp;
137 ARCH_CTXCTRL_EXCRET_PATTERN(p_statctx, ctx[0], ctx[1], ctx[2], ctx[3],
138 svc_func, tfm_svc_thread_mode_spm_return);
139
140 arch_update_process_sp(sp, sp_limit);
141 }
142
prepare_to_thread_mode_spm(uint8_t svc_number,uint32_t * ctx,uint32_t exc_return)143 static int32_t prepare_to_thread_mode_spm(uint8_t svc_number, uint32_t *ctx, uint32_t exc_return)
144 {
145 fih_int fih_rc = FIH_FAILURE;
146 FIH_RET_TYPE(bool) fih_bool;
147 const struct partition_t *p_curr_sp;
148 psa_api_svc_func_t svc_func = NULL;
149 uint8_t svc_idx = svc_number & TFM_SVC_NUM_INDEX_MSK;
150
151 if (TFM_SVC_IS_HANDLER_MODE(svc_number)) {
152 /* PSA APIs are not allowed to be called from Handler mode */
153 tfm_core_panic();
154 }
155
156 if (svc_idx >= (sizeof(psa_api_svc_func_table)/sizeof(psa_api_svc_func_t))) {
157 ERROR_RAW("Invalid PSA API SVC requested: 0x%08x\n", svc_number);
158 ctx[0] = (uint32_t)PSA_ERROR_GENERIC_ERROR;
159 return exc_return;
160 }
161
162 svc_func = psa_api_svc_func_table[svc_idx];
163 if (!svc_func) {
164 ERROR_RAW("Corresponding SVC function is not included for number 0x%08x\n", svc_number);
165 ctx[0] = (uint32_t)PSA_ERROR_GENERIC_ERROR;
166 return exc_return;
167 }
168
169 saved_exc_return = exc_return;
170
171 p_curr_sp = GET_CURRENT_COMPONENT();
172 FIH_CALL(tfm_hal_boundary_need_switch, fih_bool, p_curr_sp->boundary, get_spm_boundary());
173 if (fih_not_eq(fih_bool, fih_int_encode(false))) {
174 FIH_CALL(tfm_hal_activate_boundary, fih_rc, NULL, get_spm_boundary());
175 if (fih_not_eq(fih_rc, fih_int_encode(TFM_HAL_SUCCESS))) {
176 tfm_core_panic();
177 }
178 }
179
180 init_spm_func_context(svc_func, ctx);
181
182 ctx[0] = (uint32_t)PSA_SUCCESS;
183
184 return EXC_RETURN_THREAD_PSP;
185 }
186
tfm_svc_thread_mode_spm_active(void)187 bool tfm_svc_thread_mode_spm_active(void)
188 {
189 return saved_psp != INVALID_PSP_VALUE;
190 }
191 #endif
192
handle_spm_svc_requests(uint32_t svc_number,uint32_t exc_return,uint32_t * svc_args,uint32_t * msp)193 static uint32_t handle_spm_svc_requests(uint32_t svc_number, uint32_t exc_return,
194 uint32_t *svc_args, uint32_t *msp)
195 {
196 #if TFM_SP_LOG_RAW_ENABLED
197 struct partition_t *curr_partition;
198 fih_int fih_rc = FIH_FAILURE;
199 #endif
200
201 switch (svc_number) {
202 case TFM_SVC_SPM_INIT:
203 exc_return = tfm_spm_init();
204 tfm_arch_check_msp_sealing();
205 /* The following call does not return */
206 tfm_arch_free_msp_and_exc_ret(SPM_BOOT_STACK_BOTTOM, exc_return);
207 break;
208 case TFM_SVC_GET_BOOT_DATA:
209 tfm_core_get_boot_data_handler(svc_args);
210 break;
211 #if (TFM_ISOLATION_LEVEL != 1) && (CONFIG_TFM_FLIH_API == 1)
212 case TFM_SVC_PREPARE_DEPRIV_FLIH:
213 exc_return = tfm_flih_prepare_depriv_flih((struct partition_t *)svc_args[0],
214 (uintptr_t)svc_args[1]);
215 break;
216 case TFM_SVC_FLIH_FUNC_RETURN:
217 exc_return = tfm_flih_return_to_isr(svc_args[0], (struct context_flih_ret_t *)msp);
218 break;
219 #endif
220 #if TFM_SP_LOG_RAW_ENABLED
221 case TFM_SVC_OUTPUT_UNPRIV_STRING:
222 /* Protect PRoT data from unauthorised access from ARoT partition.
223 * This fixes the TFMV-7 vulnerability
224 */
225 curr_partition = GET_CURRENT_COMPONENT();
226 FIH_CALL(tfm_hal_memory_check, fih_rc, curr_partition->boundary, (uintptr_t)svc_args[0],
227 svc_args[1], TFM_HAL_ACCESS_READABLE);
228 if (fih_eq(fih_rc, fih_int_encode(PSA_SUCCESS))) {
229 svc_args[0] = tfm_hal_output_spm_log((const char *)svc_args[0], svc_args[1]);
230 } else {
231 tfm_core_panic();
232 }
233 break;
234 #endif
235 #if TFM_ISOLATION_LEVEL > 1
236 case TFM_SVC_THREAD_MODE_SPM_RETURN:
237 exc_return = thread_mode_spm_return(svc_args[0]);
238 break;
239 #endif
240 default:
241 ERROR_RAW("Unknown SPM SVC requested: 0x%08x\n", svc_number);
242 svc_args[0] = (uint32_t)PSA_ERROR_GENERIC_ERROR;
243 }
244
245 return exc_return;
246 }
247
spm_svc_handler(uint32_t * msp,uint32_t exc_return,uint32_t * psp)248 uint32_t spm_svc_handler(uint32_t *msp, uint32_t exc_return, uint32_t *psp)
249 {
250 uint8_t svc_number = TFM_SVC_PSA_FRAMEWORK_VERSION;
251 uint32_t *svc_args = msp;
252
253 if ((exc_return & EXC_RETURN_MODE) && (exc_return & EXC_RETURN_SPSEL)) {
254 /* Use PSP when both EXC_RETURN.MODE and EXC_RETURN.SPSEL are set */
255 svc_args = psp;
256 }
257
258 if (is_return_secure_stack(exc_return)) {
259 if (is_default_stacking_rules_apply(exc_return) == false) {
260 /* In this case offset the svc_args and only use
261 * the caller-saved registers
262 */
263 svc_args = &svc_args[10];
264 }
265
266 /* SV called directly from secure context. Check instruction for
267 * svc_number
268 */
269 svc_number = ((uint8_t *)svc_args[6])[-2];
270 } else {
271 /* Secure SV executing with NS return.
272 * NS cannot directly trigger S SVC so this should not happen. This is
273 * an unrecoverable error.
274 */
275 tfm_core_panic();
276 }
277
278 if (!!(exc_return & EXC_RETURN_MODE) == TFM_SVC_IS_HANDLER_MODE(svc_number)) {
279 /* Mode of caller does match mode of the target SVC */
280 tfm_core_panic();
281 }
282
283 if (TFM_SVC_IS_SPM(svc_number)) {
284 /* SPM SVC */
285 return handle_spm_svc_requests(svc_number, exc_return, svc_args, msp);
286 }
287
288 #if TFM_ISOLATION_LEVEL > 1
289 if (TFM_SVC_IS_PSA_API(svc_number)) {
290 if (((uint32_t)®ION_NAME(Image$$, ARM_LIB_STACK, $$ZI$$Limit) - (uint32_t)msp) > 0) {
291 /* The Main Stack has contents, not calling from Partition thread */
292 tfm_core_panic();
293 }
294
295 return prepare_to_thread_mode_spm(svc_number, svc_args, exc_return);
296 }
297 #endif
298
299 #ifdef PLATFORM_SVC_HANDLERS
300 if (TFM_SVC_IS_PLATFORM(svc_number)) {
301 svc_args[0] = (platform_svc_handlers(svc_number, svc_args, exc_return));
302 return exc_return;
303 }
304 #endif
305
306 ERROR_RAW("Unknown SVC number requested: 0x%08x\n", svc_number);
307 svc_args[0] = (uint32_t)PSA_ERROR_GENERIC_ERROR;
308
309 return exc_return;
310 }
311
312 __attribute__((naked))
tfm_svc_thread_mode_spm_return(psa_status_t result)313 void tfm_svc_thread_mode_spm_return(psa_status_t result)
314 {
315 __ASM volatile("SVC "M2S(TFM_SVC_THREAD_MODE_SPM_RETURN)" \n");
316 }
317