1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25 #include <trusty/arm_ffa.h>
26 #include <trusty/sm_err.h>
27 #include <trusty/smc.h>
28 #include <trusty/smcall.h>
29 #include <trusty/trusty_dev.h>
30 #include <trusty/trusty_mem.h>
31 #include <trusty/util.h>
32
33 struct trusty_dev;
34
35 #define LOCAL_LOG 0
36
37 /*
38 * Select RXTX map smc variant based on register size. Note that the FF-A spec
39 * does not support passing a 64 bit paddr from a 32 bit client, so the
40 * allocated buffer has to be below 4G if this is called from 32 bit code.
41 */
42 #define SMC_FCZ_FFA_RXTX_MAP \
43 ((sizeof(unsigned long) <= 4) ? SMC_FC_FFA_RXTX_MAP : SMC_FC64_FFA_RXTX_MAP)
44
trusty_fast_call32(struct trusty_dev * dev,uint32_t smcnr,uint32_t a0,uint32_t a1,uint32_t a2)45 static int32_t trusty_fast_call32(struct trusty_dev* dev,
46 uint32_t smcnr,
47 uint32_t a0,
48 uint32_t a1,
49 uint32_t a2) {
50 trusty_assert(dev);
51 trusty_assert(SMC_IS_FASTCALL(smcnr));
52
53 return smc(smcnr, a0, a1, a2);
54 }
55
trusty_std_call_inner(struct trusty_dev * dev,unsigned long smcnr,unsigned long a0,unsigned long a1,unsigned long a2)56 static unsigned long trusty_std_call_inner(struct trusty_dev* dev,
57 unsigned long smcnr,
58 unsigned long a0,
59 unsigned long a1,
60 unsigned long a2) {
61 unsigned long ret;
62 int retry = 5;
63
64 trusty_debug("%s(0x%lx 0x%lx 0x%lx 0x%lx)\n", __func__, smcnr, a0, a1, a2);
65
66 while (true) {
67 ret = smc(smcnr, a0, a1, a2);
68 while ((int32_t)ret == SM_ERR_FIQ_INTERRUPTED)
69 ret = smc(SMC_SC_RESTART_FIQ, 0, 0, 0);
70 if ((int)ret != SM_ERR_BUSY || !retry)
71 break;
72
73 trusty_debug("%s(0x%lx 0x%lx 0x%lx 0x%lx) returned busy, retry\n",
74 __func__, smcnr, a0, a1, a2);
75
76 retry--;
77 }
78
79 return ret;
80 }
81
trusty_std_call_helper(struct trusty_dev * dev,unsigned long smcnr,unsigned long a0,unsigned long a1,unsigned long a2)82 static unsigned long trusty_std_call_helper(struct trusty_dev* dev,
83 unsigned long smcnr,
84 unsigned long a0,
85 unsigned long a1,
86 unsigned long a2) {
87 unsigned long ret;
88 unsigned long irq_state;
89
90 while (true) {
91 trusty_local_irq_disable(&irq_state);
92 ret = trusty_std_call_inner(dev, smcnr, a0, a1, a2);
93 trusty_local_irq_restore(&irq_state);
94
95 if ((int)ret != SM_ERR_BUSY)
96 break;
97
98 trusty_idle(dev, false);
99 }
100
101 return ret;
102 }
103
trusty_std_call32(struct trusty_dev * dev,uint32_t smcnr,uint32_t a0,uint32_t a1,uint32_t a2)104 static int32_t trusty_std_call32(struct trusty_dev* dev,
105 uint32_t smcnr,
106 uint32_t a0,
107 uint32_t a1,
108 uint32_t a2) {
109 int ret;
110
111 trusty_assert(dev);
112 trusty_assert(!SMC_IS_FASTCALL(smcnr));
113
114 if (smcnr != SMC_SC_NOP) {
115 trusty_lock(dev);
116 }
117
118 trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) started\n", __func__, smcnr, a0, a1,
119 a2);
120
121 ret = trusty_std_call_helper(dev, smcnr, a0, a1, a2);
122 while (ret == SM_ERR_INTERRUPTED || ret == SM_ERR_CPU_IDLE) {
123 trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) interrupted\n", __func__, smcnr,
124 a0, a1, a2);
125 if (ret == SM_ERR_CPU_IDLE) {
126 trusty_idle(dev, false);
127 }
128 ret = trusty_std_call_helper(dev, SMC_SC_RESTART_LAST, 0, 0, 0);
129 }
130
131 trusty_debug("%s(0x%x 0x%x 0x%x 0x%x) returned 0x%x\n", __func__, smcnr, a0,
132 a1, a2, ret);
133
134 if (smcnr != SMC_SC_NOP) {
135 trusty_unlock(dev);
136 }
137
138 return ret;
139 }
140
trusty_call32_mem_buf_id(struct trusty_dev * dev,uint32_t smcnr,trusty_shared_mem_id_t buf_id,uint32_t size)141 static int trusty_call32_mem_buf_id(struct trusty_dev* dev,
142 uint32_t smcnr,
143 trusty_shared_mem_id_t buf_id,
144 uint32_t size) {
145 trusty_assert(dev);
146
147 if (SMC_IS_FASTCALL(smcnr)) {
148 return trusty_fast_call32(dev, smcnr, (uint32_t)buf_id,
149 (uint32_t)(buf_id >> 32), size);
150 } else {
151 return trusty_std_call32(dev, smcnr, (uint32_t)buf_id,
152 (uint32_t)(buf_id >> 32), size);
153 }
154 }
155
trusty_dev_init_ipc(struct trusty_dev * dev,trusty_shared_mem_id_t buf_id,uint32_t buf_size)156 int trusty_dev_init_ipc(struct trusty_dev* dev,
157 trusty_shared_mem_id_t buf_id,
158 uint32_t buf_size) {
159 return trusty_call32_mem_buf_id(dev, SMC_SC_TRUSTY_IPC_CREATE_QL_DEV,
160 buf_id, buf_size);
161 }
162
trusty_dev_exec_ipc(struct trusty_dev * dev,trusty_shared_mem_id_t buf_id,uint32_t buf_size)163 int trusty_dev_exec_ipc(struct trusty_dev* dev,
164 trusty_shared_mem_id_t buf_id,
165 uint32_t buf_size) {
166 return trusty_call32_mem_buf_id(dev, SMC_SC_TRUSTY_IPC_HANDLE_QL_DEV_CMD,
167 buf_id, buf_size);
168 }
169
trusty_dev_exec_fc_ipc(struct trusty_dev * dev,trusty_shared_mem_id_t buf_id,uint32_t buf_size)170 int trusty_dev_exec_fc_ipc(struct trusty_dev* dev,
171 trusty_shared_mem_id_t buf_id,
172 uint32_t buf_size) {
173 return trusty_call32_mem_buf_id(dev, SMC_FC_HANDLE_QL_TIPC_DEV_CMD, buf_id,
174 buf_size);
175 }
176
trusty_dev_shutdown_ipc(struct trusty_dev * dev,trusty_shared_mem_id_t buf_id,uint32_t buf_size)177 int trusty_dev_shutdown_ipc(struct trusty_dev* dev,
178 trusty_shared_mem_id_t buf_id,
179 uint32_t buf_size) {
180 return trusty_call32_mem_buf_id(dev, SMC_SC_TRUSTY_IPC_SHUTDOWN_QL_DEV,
181 buf_id, buf_size);
182 }
183
trusty_init_api_version(struct trusty_dev * dev)184 static int trusty_init_api_version(struct trusty_dev* dev) {
185 uint32_t api_version;
186
187 api_version = trusty_fast_call32(dev, SMC_FC_API_VERSION,
188 TRUSTY_API_VERSION_CURRENT, 0, 0);
189 if (api_version == SM_ERR_UNDEFINED_SMC)
190 api_version = 0;
191
192 if (api_version > TRUSTY_API_VERSION_CURRENT) {
193 trusty_error("unsupported trusty api version %u > %u\n", api_version,
194 TRUSTY_API_VERSION_CURRENT);
195 return -1;
196 }
197
198 trusty_info("selected trusty api version: %u (requested %u)\n", api_version,
199 TRUSTY_API_VERSION_CURRENT);
200
201 dev->api_version = api_version;
202
203 return 0;
204 }
205
trusty_dev_init(struct trusty_dev * dev,void * priv_data)206 int trusty_dev_init(struct trusty_dev* dev, void* priv_data) {
207 int ret;
208 struct smc_ret8 smc_ret;
209 struct ns_mem_page_info tx_pinfo;
210 struct ns_mem_page_info rx_pinfo;
211 const size_t rxtx_page_count = 1;
212 trusty_assert(dev);
213
214 dev->priv_data = priv_data;
215 dev->ffa_tx = NULL;
216 ret = trusty_init_api_version(dev);
217 if (ret) {
218 return ret;
219 }
220 if (dev->api_version < TRUSTY_API_VERSION_MEM_OBJ) {
221 return 0;
222 }
223
224 /* Get supported FF-A version and check if it is compatible */
225 smc_ret = smc8(SMC_FC_FFA_VERSION, FFA_CURRENT_VERSION, 0, 0, 0, 0, 0, 0);
226 if (FFA_VERSION_TO_MAJOR(smc_ret.r0) != FFA_CURRENT_VERSION_MAJOR) {
227 /* TODO: support more than one (minor) version. */
228 trusty_error("%s: unsupported FF-A version 0x%lx, expected 0x%x\n",
229 __func__, smc_ret.r0, FFA_CURRENT_VERSION);
230 goto err_version;
231 }
232
233 /* Check that SMC_FC_FFA_MEM_SHARE is implemented */
234 smc_ret = smc8(SMC_FC_FFA_FEATURES, SMC_FC_FFA_MEM_SHARE, 0, 0, 0, 0, 0, 0);
235 if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) {
236 trusty_error(
237 "%s: SMC_FC_FFA_FEATURES(SMC_FC_FFA_MEM_SHARE) failed 0x%lx 0x%lx 0x%lx\n",
238 __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2);
239 goto err_features;
240 }
241
242 /*
243 * Set FF-A endpoint IDs.
244 *
245 * Hardcode 0x8000 for the secure os.
246 * TODO: Use FFA call or device tree to configure this dynamically
247 */
248 smc_ret = smc8(SMC_FC_FFA_ID_GET, 0, 0, 0, 0, 0, 0, 0);
249 if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) {
250 trusty_error("%s: SMC_FC_FFA_ID_GET failed 0x%lx 0x%lx 0x%lx\n",
251 __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2);
252 goto err_id_get;
253 }
254 dev->ffa_local_id = smc_ret.r2;
255 dev->ffa_remote_id = 0x8000;
256
257 dev->ffa_tx = trusty_alloc_pages(rxtx_page_count);
258 if (!dev->ffa_tx) {
259 goto err_alloc_ffa_tx;
260 }
261 dev->ffa_rx = trusty_alloc_pages(rxtx_page_count);
262 if (!dev->ffa_rx) {
263 goto err_alloc_ffa_rx;
264 }
265 ret = trusty_encode_page_info(&tx_pinfo, dev->ffa_tx);
266 if (ret) {
267 goto err_encode_page_info;
268 }
269 ret = trusty_encode_page_info(&rx_pinfo, dev->ffa_rx);
270 if (ret) {
271 goto err_encode_page_info;
272 }
273
274 /*
275 * TODO: check or pass memory attributes. The FF-A spec says the buffer has
276 * to be cached, but we currently have callers that don't match this.
277 */
278
279 smc_ret = smc8(SMC_FCZ_FFA_RXTX_MAP, tx_pinfo.paddr, rx_pinfo.paddr,
280 rxtx_page_count, 0, 0, 0, 0);
281 if (smc_ret.r0 != SMC_FC_FFA_SUCCESS) {
282 trusty_error("%s: FFA_RXTX_MAP failed 0x%lx 0x%lx 0x%lx\n", __func__,
283 smc_ret.r0, smc_ret.r1, smc_ret.r2);
284 goto err_rxtx_map;
285 }
286
287 if (ret) {
288 goto err_setup_msg_buf;
289 }
290 return 0;
291
292 err_setup_msg_buf:
293 err_rxtx_map:
294 err_encode_page_info:
295 err_alloc_ffa_rx:
296 err_alloc_ffa_tx:
297 err_id_get:
298 err_features:
299 err_version:
300 trusty_fatal("%s: init failed\n", __func__, ret);
301 }
302
trusty_dev_shutdown(struct trusty_dev * dev)303 int trusty_dev_shutdown(struct trusty_dev* dev) {
304 trusty_assert(dev);
305
306 if (dev->ffa_tx) {
307 smc(SMC_FC_FFA_RXTX_UNMAP, 0, 0, 0);
308 }
309 dev->priv_data = NULL;
310 return 0;
311 }
312
trusty_dev_nop(struct trusty_dev * dev)313 int trusty_dev_nop(struct trusty_dev* dev) {
314 int ret = trusty_std_call32(dev, SMC_SC_NOP, 0, 0, 0);
315 return ret == SM_ERR_NOP_DONE ? 0 : ret == SM_ERR_NOP_INTERRUPTED ? 1 : -1;
316 }
317
trusty_dev_share_memory(struct trusty_dev * dev,trusty_shared_mem_id_t * idp,struct ns_mem_page_info * pinfo,size_t page_count)318 int trusty_dev_share_memory(struct trusty_dev* dev,
319 trusty_shared_mem_id_t* idp,
320 struct ns_mem_page_info* pinfo,
321 size_t page_count) {
322 struct smc_ret8 smc_ret;
323 struct ffa_mtd* mtd = dev->ffa_tx;
324 size_t comp_mrd_offset = offsetof(struct ffa_mtd, emad[1]);
325 struct ffa_comp_mrd* comp_mrd = dev->ffa_tx + comp_mrd_offset;
326 struct ffa_cons_mrd* cons_mrd = comp_mrd->address_range_array;
327 size_t tx_size = ((void*)cons_mrd - dev->ffa_tx) + sizeof(*cons_mrd);
328
329 if (!dev->ffa_tx) {
330 /*
331 * If the trusty api version is before TRUSTY_API_VERSION_MEM_OBJ, fall
332 * back to old api of passing the 64 bit paddr/attr value directly.
333 */
334 *idp = pinfo->attr;
335 return 0;
336 }
337
338 trusty_memset(mtd, 0, tx_size);
339 mtd->sender_id = dev->ffa_local_id;
340 mtd->memory_region_attributes = pinfo->ffa_mem_attr;
341 mtd->emad_count = 1;
342 mtd->emad[0].mapd.endpoint_id = dev->ffa_remote_id;
343 mtd->emad[0].mapd.memory_access_permissions = pinfo->ffa_mem_perm;
344 mtd->emad[0].comp_mrd_offset = comp_mrd_offset;
345 comp_mrd->total_page_count = page_count;
346 comp_mrd->address_range_count = 1;
347 cons_mrd->address = pinfo->paddr;
348 cons_mrd->page_count = page_count;
349
350 /*
351 * Tell the SPM/Hypervisor to share the memory.
352 */
353 smc_ret = smc8(SMC_FC_FFA_MEM_SHARE, tx_size, tx_size, 0, 0, 0, 0, 0);
354 if ((unsigned int)smc_ret.r0 != SMC_FC_FFA_SUCCESS) {
355 trusty_error("%s: SMC_FC_FFA_MEM_SHARE failed 0x%lx 0x%lx 0x%lx\n",
356 __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2);
357 return -1;
358 }
359
360 *idp = smc_ret.r2;
361
362 return 0;
363 }
364
trusty_dev_reclaim_memory(struct trusty_dev * dev,trusty_shared_mem_id_t id)365 int trusty_dev_reclaim_memory(struct trusty_dev* dev,
366 trusty_shared_mem_id_t id) {
367 struct smc_ret8 smc_ret;
368
369 if (!dev->ffa_tx) {
370 /*
371 * If the trusty api version is before TRUSTY_API_VERSION_MEM_OBJ, fall
372 * back to old api.
373 */
374 return 0;
375 }
376
377 /*
378 * Tell the SPM/Hypervisor to reclaim the memory. If the memory is still in
379 * use this will fail.
380 */
381 smc_ret =
382 smc8(SMC_FC_FFA_MEM_RECLAIM, (uint32_t)id, id >> 32, 0, 0, 0, 0, 0);
383 if ((unsigned int)smc_ret.r0 != SMC_FC_FFA_SUCCESS) {
384 trusty_error("%s: SMC_FC_FFA_MEM_RECLAIM failed 0x%lx 0x%lx 0x%lx\n",
385 __func__, smc_ret.r0, smc_ret.r1, smc_ret.r2);
386 return -1;
387 }
388
389 return 0;
390 }
391