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