2 * Copyright (c) 2014, Linaro Limited
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
30 #include <kernel/misc.h>
31 #include <kernel/thread.h>
32 #include <kernel/trace_ta.h>
33 #include <tee/tee_svc.h>
34 #include <tee/arch_svc.h>
35 #include <tee/tee_svc_cryp.h>
36 #include <tee/tee_svc_storage.h>
37 #include <tee/se/svc.h>
38 #include <tee/svc_cache.h>
39 #include <tee_syscall_numbers.h>
43 #include "arch_svc_private.h"
45 #if (TRACE_LEVEL == TRACE_FLOW) && defined(CFG_TEE_CORE_TA_TRACE)
46 #define TRACE_SYSCALLS
49 struct syscall_entry {
57 #define SYSCALL_ENTRY(_fn) { .fn = (syscall_t)_fn, .name = #_fn }
59 #define SYSCALL_ENTRY(_fn) { .fn = (syscall_t)_fn }
63 * This array is ordered according to the SYSCALL ids TEE_SCN_xxx
65 static const struct syscall_entry tee_svc_syscall_table[] = {
66 SYSCALL_ENTRY(syscall_sys_return),
67 SYSCALL_ENTRY(syscall_log),
68 SYSCALL_ENTRY(syscall_panic),
69 SYSCALL_ENTRY(syscall_get_property),
70 SYSCALL_ENTRY(syscall_get_property_name_to_index),
71 SYSCALL_ENTRY(syscall_open_ta_session),
72 SYSCALL_ENTRY(syscall_close_ta_session),
73 SYSCALL_ENTRY(syscall_invoke_ta_command),
74 SYSCALL_ENTRY(syscall_check_access_rights),
75 SYSCALL_ENTRY(syscall_get_cancellation_flag),
76 SYSCALL_ENTRY(syscall_unmask_cancellation),
77 SYSCALL_ENTRY(syscall_mask_cancellation),
78 SYSCALL_ENTRY(syscall_wait),
79 SYSCALL_ENTRY(syscall_get_time),
80 SYSCALL_ENTRY(syscall_set_ta_time),
81 SYSCALL_ENTRY(syscall_cryp_state_alloc),
82 SYSCALL_ENTRY(syscall_cryp_state_copy),
83 SYSCALL_ENTRY(syscall_cryp_state_free),
84 SYSCALL_ENTRY(syscall_hash_init),
85 SYSCALL_ENTRY(syscall_hash_update),
86 SYSCALL_ENTRY(syscall_hash_final),
87 SYSCALL_ENTRY(syscall_cipher_init),
88 SYSCALL_ENTRY(syscall_cipher_update),
89 SYSCALL_ENTRY(syscall_cipher_final),
90 SYSCALL_ENTRY(syscall_cryp_obj_get_info),
91 SYSCALL_ENTRY(syscall_cryp_obj_restrict_usage),
92 SYSCALL_ENTRY(syscall_cryp_obj_get_attr),
93 SYSCALL_ENTRY(syscall_cryp_obj_alloc),
94 SYSCALL_ENTRY(syscall_cryp_obj_close),
95 SYSCALL_ENTRY(syscall_cryp_obj_reset),
96 SYSCALL_ENTRY(syscall_cryp_obj_populate),
97 SYSCALL_ENTRY(syscall_cryp_obj_copy),
98 SYSCALL_ENTRY(syscall_cryp_derive_key),
99 SYSCALL_ENTRY(syscall_cryp_random_number_generate),
100 SYSCALL_ENTRY(syscall_authenc_init),
101 SYSCALL_ENTRY(syscall_authenc_update_aad),
102 SYSCALL_ENTRY(syscall_authenc_update_payload),
103 SYSCALL_ENTRY(syscall_authenc_enc_final),
104 SYSCALL_ENTRY(syscall_authenc_dec_final),
105 SYSCALL_ENTRY(syscall_asymm_operate),
106 SYSCALL_ENTRY(syscall_asymm_verify),
107 SYSCALL_ENTRY(syscall_storage_obj_open),
108 SYSCALL_ENTRY(syscall_storage_obj_create),
109 SYSCALL_ENTRY(syscall_storage_obj_del),
110 SYSCALL_ENTRY(syscall_storage_obj_rename),
111 SYSCALL_ENTRY(syscall_storage_alloc_enum),
112 SYSCALL_ENTRY(syscall_storage_free_enum),
113 SYSCALL_ENTRY(syscall_storage_reset_enum),
114 SYSCALL_ENTRY(syscall_storage_start_enum),
115 SYSCALL_ENTRY(syscall_storage_next_enum),
116 SYSCALL_ENTRY(syscall_storage_obj_read),
117 SYSCALL_ENTRY(syscall_storage_obj_write),
118 SYSCALL_ENTRY(syscall_storage_obj_trunc),
119 SYSCALL_ENTRY(syscall_storage_obj_seek),
120 SYSCALL_ENTRY(syscall_obj_generate_key),
121 SYSCALL_ENTRY(syscall_se_service_open),
122 SYSCALL_ENTRY(syscall_se_service_close),
123 SYSCALL_ENTRY(syscall_se_service_get_readers),
124 SYSCALL_ENTRY(syscall_se_reader_get_prop),
125 SYSCALL_ENTRY(syscall_se_reader_get_name),
126 SYSCALL_ENTRY(syscall_se_reader_open_session),
127 SYSCALL_ENTRY(syscall_se_reader_close_sessions),
128 SYSCALL_ENTRY(syscall_se_session_is_closed),
129 SYSCALL_ENTRY(syscall_se_session_get_atr),
130 SYSCALL_ENTRY(syscall_se_session_open_channel),
131 SYSCALL_ENTRY(syscall_se_session_close),
132 SYSCALL_ENTRY(syscall_se_channel_select_next),
133 SYSCALL_ENTRY(syscall_se_channel_get_select_resp),
134 SYSCALL_ENTRY(syscall_se_channel_transmit),
135 SYSCALL_ENTRY(syscall_se_channel_close),
136 SYSCALL_ENTRY(syscall_cache_operation),
139 #ifdef TRACE_SYSCALLS
140 static void trace_syscall(size_t num)
142 if (num == TEE_SCN_RETURN || num > TEE_SCN_MAX)
144 FMSG("syscall #%zu (%s)", num, tee_svc_syscall_table[num].name);
147 static void trace_syscall(size_t num __unused)
153 static void get_scn_max_args(struct thread_svc_regs *regs, size_t *scn,
157 *max_args = regs->r6;
162 static void get_scn_max_args(struct thread_svc_regs *regs, size_t *scn,
165 if (((regs->spsr >> SPSR_MODE_RW_SHIFT) & SPSR_MODE_RW_MASK) ==
168 *max_args = regs->x6;
177 static void set_svc_retval(struct thread_svc_regs *regs, uint32_t ret_val)
184 static void set_svc_retval(struct thread_svc_regs *regs, uint64_t ret_val)
190 void tee_svc_handler(struct thread_svc_regs *regs)
196 COMPILE_TIME_ASSERT(ARRAY_SIZE(tee_svc_syscall_table) ==
199 thread_user_save_vfp();
201 /* TA has just entered kernel mode */
202 tee_ta_update_session_utime_suspend();
204 /* Restore foreign interrupts which are disabled on exception entry */
205 thread_restore_foreign_intr();
207 get_scn_max_args(regs, &scn, &max_args);
211 if (max_args > TEE_SVC_MAX_ARGS) {
212 DMSG("Too many arguments for SCN %zu (%zu)", scn, max_args);
213 set_svc_retval(regs, TEE_ERROR_GENERIC);
217 if (scn > TEE_SCN_MAX)
218 scf = syscall_not_supported;
220 scf = tee_svc_syscall_table[scn].fn;
222 set_svc_retval(regs, tee_svc_do_call(regs, scf));
224 if (scn != TEE_SCN_RETURN) {
225 /* We're about to switch back to user mode */
226 tee_ta_update_session_utime_resume();
231 uint32_t tee_svc_sys_return_helper(uint32_t ret, bool panic,
232 uint32_t panic_code, struct thread_svc_regs *regs)
235 TAMSG("TA panicked with code 0x%x usr_sp 0x%x usr_lr 0x%x",
236 panic_code, read_mode_sp(CPSR_MODE_SYS),
237 read_mode_lr(CPSR_MODE_SYS));
240 regs->r2 = panic_code;
241 regs->lr = (uintptr_t)thread_unwind_user_mode;
242 regs->spsr = read_cpsr();
247 uint32_t tee_svc_sys_return_helper(uint32_t ret, bool panic,
248 uint32_t panic_code, struct thread_svc_regs *regs)
251 TAMSG("TA panicked with code 0x%x usr_sp 0x%" PRIx64 " usr_lr 0x%" PRIx64,
252 panic_code, regs->x13, regs->x14);
255 regs->x2 = panic_code;
256 regs->elr = (uintptr_t)thread_unwind_user_mode;
257 regs->spsr = SPSR_64(SPSR_64_MODE_EL1, SPSR_64_MODE_SP_EL0, 0);
258 regs->spsr |= read_daif();
260 * Regs is the value of stack pointer before calling the SVC
261 * handler. By the addition matches for the reserved space at the
262 * beginning of el0_sync_svc(). This prepares the stack when
263 * returning to thread_unwind_user_mode instead of a normal
266 regs->sp_el0 = (uint64_t)(regs + 1);