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)&REGION_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