xref: /optee_os/core/arch/arm/tee/entry_fast.c (revision b99a4a1850c2ce661156ebc25f48d47efa8a41c1)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2015, Linaro Limited
4  * Copyright (c) 2014, STMicroelectronics International N.V.
5  */
6 
7 #include <tee/entry_fast.h>
8 #include <optee_msg.h>
9 #include <sm/optee_smc.h>
10 #include <kernel/generic_boot.h>
11 #include <kernel/tee_l2cc_mutex.h>
12 #include <kernel/virtualization.h>
13 #include <kernel/misc.h>
14 #include <mm/core_mmu.h>
15 
16 static void tee_entry_get_shm_config(struct thread_smc_args *args)
17 {
18 	args->a0 = OPTEE_SMC_RETURN_OK;
19 	args->a1 = default_nsec_shm_paddr;
20 	args->a2 = default_nsec_shm_size;
21 	/* Should this be TEESMC cache attributes instead? */
22 	args->a3 = core_mmu_is_shm_cached();
23 }
24 
25 static void tee_entry_fastcall_l2cc_mutex(struct thread_smc_args *args)
26 {
27 	TEE_Result ret;
28 #ifdef ARM32
29 	paddr_t pa = 0;
30 
31 	switch (args->a1) {
32 	case OPTEE_SMC_L2CC_MUTEX_GET_ADDR:
33 		ret = tee_get_l2cc_mutex(&pa);
34 		reg_pair_from_64(pa, &args->a2, &args->a3);
35 		break;
36 	case OPTEE_SMC_L2CC_MUTEX_SET_ADDR:
37 		pa = reg_pair_to_64(args->a2, args->a3);
38 		ret = tee_set_l2cc_mutex(&pa);
39 		break;
40 	case OPTEE_SMC_L2CC_MUTEX_ENABLE:
41 		ret = tee_enable_l2cc_mutex();
42 		break;
43 	case OPTEE_SMC_L2CC_MUTEX_DISABLE:
44 		ret = tee_disable_l2cc_mutex();
45 		break;
46 	default:
47 		args->a0 = OPTEE_SMC_RETURN_EBADCMD;
48 		return;
49 	}
50 #else
51 	ret = TEE_ERROR_NOT_SUPPORTED;
52 #endif
53 	if (ret == TEE_ERROR_NOT_SUPPORTED)
54 		args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION;
55 	else if (ret)
56 		args->a0 = OPTEE_SMC_RETURN_EBADADDR;
57 	else
58 		args->a0 = OPTEE_SMC_RETURN_OK;
59 }
60 
61 static void tee_entry_exchange_capabilities(struct thread_smc_args *args)
62 {
63 	bool dyn_shm_en = false;
64 
65 	/*
66 	 * Currently we ignore OPTEE_SMC_NSEC_CAP_UNIPROCESSOR.
67 	 *
68 	 * The memory mapping of shared memory is defined as normal
69 	 * shared memory for SMP systems and normal memory for UP
70 	 * systems. Currently we map all memory as shared in secure
71 	 * world.
72 	 *
73 	 * When translation tables are created with shared bit cleared for
74 	 * uniprocessor systems we'll need to check
75 	 * OPTEE_SMC_NSEC_CAP_UNIPROCESSOR.
76 	 */
77 
78 	if (args->a1 & ~OPTEE_SMC_NSEC_CAP_UNIPROCESSOR) {
79 		/* Unknown capability. */
80 		args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL;
81 		return;
82 	}
83 
84 	args->a0 = OPTEE_SMC_RETURN_OK;
85 	args->a1 = OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM;
86 
87 #if defined(CFG_DYN_SHM_CAP)
88 	dyn_shm_en = core_mmu_nsec_ddr_is_defined();
89 	if (dyn_shm_en)
90 		args->a1 |= OPTEE_SMC_SEC_CAP_DYNAMIC_SHM;
91 #endif
92 
93 	IMSG("Dynamic shared memory is %sabled", dyn_shm_en ? "en" : "dis");
94 }
95 
96 static void tee_entry_disable_shm_cache(struct thread_smc_args *args)
97 {
98 	uint64_t cookie;
99 
100 	if (!thread_disable_prealloc_rpc_cache(&cookie)) {
101 		args->a0 = OPTEE_SMC_RETURN_EBUSY;
102 		return;
103 	}
104 
105 	if (!cookie) {
106 		args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL;
107 		return;
108 	}
109 
110 	args->a0 = OPTEE_SMC_RETURN_OK;
111 	args->a1 = cookie >> 32;
112 	args->a2 = cookie;
113 }
114 
115 static void tee_entry_enable_shm_cache(struct thread_smc_args *args)
116 {
117 	if (thread_enable_prealloc_rpc_cache())
118 		args->a0 = OPTEE_SMC_RETURN_OK;
119 	else
120 		args->a0 = OPTEE_SMC_RETURN_EBUSY;
121 }
122 
123 static void tee_entry_boot_secondary(struct thread_smc_args *args)
124 {
125 #if defined(CFG_BOOT_SECONDARY_REQUEST)
126 	if (!generic_boot_core_release(args->a1, (paddr_t)(args->a3)))
127 		args->a0 = OPTEE_SMC_RETURN_OK;
128 	else
129 		args->a0 = OPTEE_SMC_RETURN_EBADCMD;
130 #else
131 	args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL;
132 #endif
133 }
134 
135 static void tee_entry_get_thread_count(struct thread_smc_args *args)
136 {
137 	args->a0 = OPTEE_SMC_RETURN_OK;
138 	args->a1 = CFG_NUM_THREADS;
139 }
140 
141 #if defined(CFG_VIRTUALIZATION)
142 static void tee_entry_vm_created(struct thread_smc_args *args)
143 {
144 	uint16_t guest_id = args->a1;
145 
146 	/* Only hypervisor can issue this request */
147 	if (args->a7 != HYP_CLNT_ID) {
148 		args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL;
149 		return;
150 	}
151 
152 	args->a0 = virt_guest_created(guest_id);
153 }
154 
155 static void tee_entry_vm_destroyed(struct thread_smc_args *args)
156 {
157 	uint16_t guest_id = args->a1;
158 
159 	/* Only hypervisor can issue this request */
160 	if (args->a7 != HYP_CLNT_ID) {
161 		args->a0 = OPTEE_SMC_RETURN_ENOTAVAIL;
162 		return;
163 	}
164 
165 	args->a0 = virt_guest_destroyed(guest_id);
166 }
167 #endif
168 
169 void tee_entry_fast(struct thread_smc_args *args)
170 {
171 	switch (args->a0) {
172 
173 	/* Generic functions */
174 	case OPTEE_SMC_CALLS_COUNT:
175 		tee_entry_get_api_call_count(args);
176 		break;
177 	case OPTEE_SMC_CALLS_UID:
178 		tee_entry_get_api_uuid(args);
179 		break;
180 	case OPTEE_SMC_CALLS_REVISION:
181 		tee_entry_get_api_revision(args);
182 		break;
183 	case OPTEE_SMC_CALL_GET_OS_UUID:
184 		tee_entry_get_os_uuid(args);
185 		break;
186 	case OPTEE_SMC_CALL_GET_OS_REVISION:
187 		tee_entry_get_os_revision(args);
188 		break;
189 
190 	/* OP-TEE specific SMC functions */
191 	case OPTEE_SMC_GET_SHM_CONFIG:
192 		tee_entry_get_shm_config(args);
193 		break;
194 	case OPTEE_SMC_L2CC_MUTEX:
195 		tee_entry_fastcall_l2cc_mutex(args);
196 		break;
197 	case OPTEE_SMC_EXCHANGE_CAPABILITIES:
198 		tee_entry_exchange_capabilities(args);
199 		break;
200 	case OPTEE_SMC_DISABLE_SHM_CACHE:
201 		tee_entry_disable_shm_cache(args);
202 		break;
203 	case OPTEE_SMC_ENABLE_SHM_CACHE:
204 		tee_entry_enable_shm_cache(args);
205 		break;
206 	case OPTEE_SMC_BOOT_SECONDARY:
207 		tee_entry_boot_secondary(args);
208 		break;
209 	case OPTEE_SMC_GET_THREAD_COUNT:
210 		tee_entry_get_thread_count(args);
211 		break;
212 
213 #if defined(CFG_VIRTUALIZATION)
214 	case OPTEE_SMC_VM_CREATED:
215 		tee_entry_vm_created(args);
216 		break;
217 	case OPTEE_SMC_VM_DESTROYED:
218 		tee_entry_vm_destroyed(args);
219 		break;
220 #endif
221 
222 	default:
223 		args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION;
224 		break;
225 	}
226 }
227 
228 size_t tee_entry_generic_get_api_call_count(void)
229 {
230 	/*
231 	 * All the different calls handled in this file. If the specific
232 	 * target has additional calls it will call this function and
233 	 * add the number of calls the target has added.
234 	 */
235 	size_t ret = 12;
236 
237 #if defined(CFG_VIRTUALIZATION)
238 	ret += 2;
239 #endif
240 
241 	return ret;
242 }
243 
244 void __weak tee_entry_get_api_call_count(struct thread_smc_args *args)
245 {
246 	args->a0 = tee_entry_generic_get_api_call_count();
247 }
248 
249 void __weak tee_entry_get_api_uuid(struct thread_smc_args *args)
250 {
251 	args->a0 = OPTEE_MSG_UID_0;
252 	args->a1 = OPTEE_MSG_UID_1;
253 	args->a2 = OPTEE_MSG_UID_2;
254 	args->a3 = OPTEE_MSG_UID_3;
255 }
256 
257 void __weak tee_entry_get_api_revision(struct thread_smc_args *args)
258 {
259 	args->a0 = OPTEE_MSG_REVISION_MAJOR;
260 	args->a1 = OPTEE_MSG_REVISION_MINOR;
261 }
262 
263 void __weak tee_entry_get_os_uuid(struct thread_smc_args *args)
264 {
265 	args->a0 = OPTEE_MSG_OS_OPTEE_UUID_0;
266 	args->a1 = OPTEE_MSG_OS_OPTEE_UUID_1;
267 	args->a2 = OPTEE_MSG_OS_OPTEE_UUID_2;
268 	args->a3 = OPTEE_MSG_OS_OPTEE_UUID_3;
269 }
270 
271 void __weak tee_entry_get_os_revision(struct thread_smc_args *args)
272 {
273 	args->a0 = CFG_OPTEE_REVISION_MAJOR;
274 	args->a1 = CFG_OPTEE_REVISION_MINOR;
275 	args->a2 = TEE_IMPL_GIT_SHA1;
276 }
277