Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2023, Arm Limited
  4 */
  5
  6#include <linux/arm_ffa.h>
  7#include <linux/err.h>
  8#include <linux/errno.h>
  9#include <linux/kernel.h>
 10#include <linux/limits.h>
 11#include <linux/mm.h>
 12#include <linux/module.h>
 13#include <linux/scatterlist.h>
 14#include <linux/slab.h>
 15#include <linux/tee_core.h>
 16#include <linux/types.h>
 17#include <linux/uuid.h>
 18#include <linux/xarray.h>
 19#include "tstee_private.h"
 20
 21#define FFA_DIRECT_REQ_ARG_NUM 5
 22#define FFA_INVALID_MEM_HANDLE U64_MAX
 23
 24static void arg_list_to_ffa_data(const u32 *args,
 25				 struct ffa_send_direct_data *data)
 26{
 27	data->data0 = args[0];
 28	data->data1 = args[1];
 29	data->data2 = args[2];
 30	data->data3 = args[3];
 31	data->data4 = args[4];
 32}
 33
 34static void arg_list_from_ffa_data(const struct ffa_send_direct_data *data,
 35				   u32 *args)
 36{
 37	args[0] = lower_32_bits(data->data0);
 38	args[1] = lower_32_bits(data->data1);
 39	args[2] = lower_32_bits(data->data2);
 40	args[3] = lower_32_bits(data->data3);
 41	args[4] = lower_32_bits(data->data4);
 42}
 43
 44static void tstee_get_version(struct tee_device *teedev,
 45			      struct tee_ioctl_version_data *vers)
 46{
 47	struct tstee *tstee = tee_get_drvdata(teedev);
 48	struct tee_ioctl_version_data v = {
 49		.impl_id = TEE_IMPL_ID_TSTEE,
 50		/* FF-A endpoint ID only uses the lower 16 bits */
 51		.impl_caps = lower_16_bits(tstee->ffa_dev->vm_id),
 52		.gen_caps = 0,
 53	};
 54
 55	*vers = v;
 56}
 57
 58static int tstee_open(struct tee_context *ctx)
 59{
 60	struct ts_context_data *ctxdata;
 61
 62	ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
 63	if (!ctxdata)
 64		return -ENOMEM;
 65
 66	xa_init_flags(&ctxdata->sess_list, XA_FLAGS_ALLOC);
 67
 68	ctx->data = ctxdata;
 69
 70	return 0;
 71}
 72
 73static void tstee_release(struct tee_context *ctx)
 74{
 75	struct ts_context_data *ctxdata = ctx->data;
 76	struct ts_session *sess;
 77	unsigned long idx;
 78
 79	if (!ctxdata)
 80		return;
 81
 82	xa_for_each(&ctxdata->sess_list, idx, sess) {
 83		xa_erase(&ctxdata->sess_list, idx);
 84		kfree(sess);
 85	}
 86
 87	xa_destroy(&ctxdata->sess_list);
 88
 89	kfree(ctxdata);
 90	ctx->data = NULL;
 91}
 92
 93static int tstee_open_session(struct tee_context *ctx,
 94			      struct tee_ioctl_open_session_arg *arg,
 95			      struct tee_param *param __always_unused)
 96{
 97	struct tstee *tstee = tee_get_drvdata(ctx->teedev);
 98	struct ffa_device *ffa_dev = tstee->ffa_dev;
 99	struct ts_context_data *ctxdata = ctx->data;
100	struct ffa_send_direct_data ffa_data;
101	struct ts_session *sess = NULL;
102	u32 ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {};
103	u32 sess_id;
104	int rc;
105
106	ffa_args[TS_RPC_CTRL_REG] =
107		TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID,
108					      TS_RPC_OP_SERVICE_INFO);
109
110	memcpy(ffa_args + TS_RPC_SERVICE_INFO_UUID0, arg->uuid, UUID_SIZE);
111
112	arg_list_to_ffa_data(ffa_args, &ffa_data);
113	rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data);
114	if (rc)
115		return rc;
116
117	arg_list_from_ffa_data(&ffa_data, ffa_args);
118
119	if (ffa_args[TS_RPC_SERVICE_INFO_RPC_STATUS] != TS_RPC_OK)
120		return -ENODEV;
121
122	if (ffa_args[TS_RPC_SERVICE_INFO_IFACE] > U8_MAX)
123		return -EINVAL;
124
125	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
126	if (!sess)
127		return -ENOMEM;
128
129	sess->iface_id = ffa_args[TS_RPC_SERVICE_INFO_IFACE];
130
131	rc = xa_alloc(&ctxdata->sess_list, &sess_id, sess, xa_limit_32b,
132		      GFP_KERNEL);
133	if (rc) {
134		kfree(sess);
135		return rc;
136	}
137
138	arg->session = sess_id;
139	arg->ret = 0;
140
141	return 0;
142}
143
144static int tstee_close_session(struct tee_context *ctx, u32 session)
145{
146	struct ts_context_data *ctxdata = ctx->data;
147	struct ts_session *sess;
148
149	/* Calls xa_lock() internally */
150	sess = xa_erase(&ctxdata->sess_list, session);
151	if (!sess)
152		return -EINVAL;
153
154	kfree(sess);
155
156	return 0;
157}
158
159static int tstee_invoke_func(struct tee_context *ctx,
160			     struct tee_ioctl_invoke_arg *arg,
161			     struct tee_param *param)
162{
163	struct tstee *tstee = tee_get_drvdata(ctx->teedev);
164	struct ffa_device *ffa_dev = tstee->ffa_dev;
165	struct ts_context_data *ctxdata = ctx->data;
166	struct ffa_send_direct_data ffa_data;
167	struct tee_shm *shm = NULL;
168	struct ts_session *sess;
169	u32 req_len, ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {};
170	int shm_id, rc;
171	u8 iface_id;
172	u64 handle;
173	u16 opcode;
174
175	xa_lock(&ctxdata->sess_list);
176	sess = xa_load(&ctxdata->sess_list, arg->session);
177
178	/*
179	 * Do this while holding the lock to make sure that the session wasn't
180	 * closed meanwhile
181	 */
182	if (sess)
183		iface_id = sess->iface_id;
184
185	xa_unlock(&ctxdata->sess_list);
186	if (!sess)
187		return -EINVAL;
188
189	opcode = lower_16_bits(arg->func);
190	shm_id = lower_32_bits(param[0].u.value.a);
191	req_len = lower_32_bits(param[0].u.value.b);
192
193	if (shm_id != 0) {
194		shm = tee_shm_get_from_id(ctx, shm_id);
195		if (IS_ERR(shm))
196			return PTR_ERR(shm);
197
198		if (shm->size < req_len) {
199			dev_err(&ffa_dev->dev,
200				"request doesn't fit into shared memory buffer\n");
201			rc = -EINVAL;
202			goto out;
203		}
204
205		handle = shm->sec_world_id;
206	} else {
207		handle = FFA_INVALID_MEM_HANDLE;
208	}
209
210	ffa_args[TS_RPC_CTRL_REG] = TS_RPC_CTRL_PACK_IFACE_OPCODE(iface_id,
211								  opcode);
212	ffa_args[TS_RPC_SERVICE_MEM_HANDLE_LSW] = lower_32_bits(handle);
213	ffa_args[TS_RPC_SERVICE_MEM_HANDLE_MSW] = upper_32_bits(handle);
214	ffa_args[TS_RPC_SERVICE_REQ_LEN] = req_len;
215	ffa_args[TS_RPC_SERVICE_CLIENT_ID] = 0;
216
217	arg_list_to_ffa_data(ffa_args, &ffa_data);
218	rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data);
219	if (rc)
220		goto out;
221
222	arg_list_from_ffa_data(&ffa_data, ffa_args);
223
224	if (ffa_args[TS_RPC_SERVICE_RPC_STATUS] != TS_RPC_OK) {
225		dev_err(&ffa_dev->dev, "invoke_func rpc status: %d\n",
226			ffa_args[TS_RPC_SERVICE_RPC_STATUS]);
227		rc = -EINVAL;
228		goto out;
229	}
230
231	arg->ret = ffa_args[TS_RPC_SERVICE_STATUS];
232	if (shm && shm->size >= ffa_args[TS_RPC_SERVICE_RESP_LEN])
233		param[0].u.value.a = ffa_args[TS_RPC_SERVICE_RESP_LEN];
234
235out:
236	if (shm)
237		tee_shm_put(shm);
238
239	return rc;
240}
241
242static int tstee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
243			      struct page **pages, size_t num_pages,
244			      unsigned long start __always_unused)
245{
246	struct tstee *tstee = tee_get_drvdata(ctx->teedev);
247	struct ffa_device *ffa_dev = tstee->ffa_dev;
248	struct ffa_mem_region_attributes mem_attr = {
249		.receiver = tstee->ffa_dev->vm_id,
250		.attrs = FFA_MEM_RW,
251		.flag = 0,
252	};
253	struct ffa_mem_ops_args mem_args = {
254		.attrs = &mem_attr,
255		.use_txbuf = true,
256		.nattrs = 1,
257		.flags = 0,
258	};
259	struct ffa_send_direct_data ffa_data;
260	struct sg_table sgt;
261	u32 ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {};
262	int rc;
263
264	rc = sg_alloc_table_from_pages(&sgt, pages, num_pages, 0,
265				       num_pages * PAGE_SIZE, GFP_KERNEL);
266	if (rc)
267		return rc;
268
269	mem_args.sg = sgt.sgl;
270	rc = ffa_dev->ops->mem_ops->memory_share(&mem_args);
271	sg_free_table(&sgt);
272	if (rc)
273		return rc;
274
275	shm->sec_world_id = mem_args.g_handle;
276
277	ffa_args[TS_RPC_CTRL_REG] =
278			TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID,
279						      TS_RPC_OP_RETRIEVE_MEM);
280	ffa_args[TS_RPC_RETRIEVE_MEM_HANDLE_LSW] =
281			lower_32_bits(shm->sec_world_id);
282	ffa_args[TS_RPC_RETRIEVE_MEM_HANDLE_MSW] =
283			upper_32_bits(shm->sec_world_id);
284	ffa_args[TS_RPC_RETRIEVE_MEM_TAG_LSW] = 0;
285	ffa_args[TS_RPC_RETRIEVE_MEM_TAG_MSW] = 0;
286
287	arg_list_to_ffa_data(ffa_args, &ffa_data);
288	rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data);
289	if (rc) {
290		(void)ffa_dev->ops->mem_ops->memory_reclaim(shm->sec_world_id,
291							    0);
292		return rc;
293	}
294
295	arg_list_from_ffa_data(&ffa_data, ffa_args);
296
297	if (ffa_args[TS_RPC_RETRIEVE_MEM_RPC_STATUS] != TS_RPC_OK) {
298		dev_err(&ffa_dev->dev, "shm_register rpc status: %d\n",
299			ffa_args[TS_RPC_RETRIEVE_MEM_RPC_STATUS]);
300		ffa_dev->ops->mem_ops->memory_reclaim(shm->sec_world_id, 0);
301		return -EINVAL;
302	}
303
304	return 0;
305}
306
307static int tstee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
308{
309	struct tstee *tstee = tee_get_drvdata(ctx->teedev);
310	struct ffa_device *ffa_dev = tstee->ffa_dev;
311	struct ffa_send_direct_data ffa_data;
312	u32 ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {};
313	int rc;
314
315	ffa_args[TS_RPC_CTRL_REG] =
316			TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID,
317						      TS_RPC_OP_RELINQ_MEM);
318	ffa_args[TS_RPC_RELINQ_MEM_HANDLE_LSW] =
319			lower_32_bits(shm->sec_world_id);
320	ffa_args[TS_RPC_RELINQ_MEM_HANDLE_MSW] =
321			upper_32_bits(shm->sec_world_id);
322
323	arg_list_to_ffa_data(ffa_args, &ffa_data);
324	rc = ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data);
325	if (rc)
326		return rc;
327	arg_list_from_ffa_data(&ffa_data, ffa_args);
328
329	if (ffa_args[TS_RPC_RELINQ_MEM_RPC_STATUS] != TS_RPC_OK) {
330		dev_err(&ffa_dev->dev, "shm_unregister rpc status: %d\n",
331			ffa_args[TS_RPC_RELINQ_MEM_RPC_STATUS]);
332		return -EINVAL;
333	}
334
335	rc = ffa_dev->ops->mem_ops->memory_reclaim(shm->sec_world_id, 0);
336
337	return rc;
338}
339
340static const struct tee_driver_ops tstee_ops = {
341	.get_version = tstee_get_version,
342	.open = tstee_open,
343	.release = tstee_release,
344	.open_session = tstee_open_session,
345	.close_session = tstee_close_session,
346	.invoke_func = tstee_invoke_func,
347};
348
349static const struct tee_desc tstee_desc = {
350	.name = "tstee-clnt",
351	.ops = &tstee_ops,
352	.owner = THIS_MODULE,
353};
354
355static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm,
356			 size_t size, size_t align)
357{
358	return tee_dyn_shm_alloc_helper(shm, size, align, tstee_shm_register);
359}
360
361static void pool_op_free(struct tee_shm_pool *pool, struct tee_shm *shm)
362{
363	tee_dyn_shm_free_helper(shm, tstee_shm_unregister);
364}
365
366static void pool_op_destroy_pool(struct tee_shm_pool *pool)
367{
368	kfree(pool);
369}
370
371static const struct tee_shm_pool_ops pool_ops = {
372	.alloc = pool_op_alloc,
373	.free = pool_op_free,
374	.destroy_pool = pool_op_destroy_pool,
375};
376
377static struct tee_shm_pool *tstee_create_shm_pool(void)
378{
379	struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);
380
381	if (!pool)
382		return ERR_PTR(-ENOMEM);
383
384	pool->ops = &pool_ops;
385
386	return pool;
387}
388
389static bool tstee_check_rpc_compatible(struct ffa_device *ffa_dev)
390{
391	struct ffa_send_direct_data ffa_data;
392	u32 ffa_args[FFA_DIRECT_REQ_ARG_NUM] = {};
393
394	ffa_args[TS_RPC_CTRL_REG] =
395			TS_RPC_CTRL_PACK_IFACE_OPCODE(TS_RPC_MGMT_IFACE_ID,
396						      TS_RPC_OP_GET_VERSION);
397
398	arg_list_to_ffa_data(ffa_args, &ffa_data);
399	if (ffa_dev->ops->msg_ops->sync_send_receive(ffa_dev, &ffa_data))
400		return false;
401
402	arg_list_from_ffa_data(&ffa_data, ffa_args);
403
404	return ffa_args[TS_RPC_GET_VERSION_RESP] == TS_RPC_PROTOCOL_VERSION;
405}
406
407static int tstee_probe(struct ffa_device *ffa_dev)
408{
409	struct tstee *tstee;
410	int rc;
411
412	ffa_dev->ops->msg_ops->mode_32bit_set(ffa_dev);
413
414	if (!tstee_check_rpc_compatible(ffa_dev))
415		return -EINVAL;
416
417	tstee = kzalloc(sizeof(*tstee), GFP_KERNEL);
418	if (!tstee)
419		return -ENOMEM;
420
421	tstee->ffa_dev = ffa_dev;
422
423	tstee->pool = tstee_create_shm_pool();
424	if (IS_ERR(tstee->pool)) {
425		rc = PTR_ERR(tstee->pool);
426		tstee->pool = NULL;
427		goto err_free_tstee;
428	}
429
430	tstee->teedev = tee_device_alloc(&tstee_desc, NULL, tstee->pool, tstee);
431	if (IS_ERR(tstee->teedev)) {
432		rc = PTR_ERR(tstee->teedev);
433		tstee->teedev = NULL;
434		goto err_free_pool;
435	}
436
437	rc = tee_device_register(tstee->teedev);
438	if (rc)
439		goto err_unreg_teedev;
440
441	ffa_dev_set_drvdata(ffa_dev, tstee);
442
443	return 0;
444
445err_unreg_teedev:
446	tee_device_unregister(tstee->teedev);
447err_free_pool:
448	tee_shm_pool_free(tstee->pool);
449err_free_tstee:
450	kfree(tstee);
451	return rc;
452}
453
454static void tstee_remove(struct ffa_device *ffa_dev)
455{
456	struct tstee *tstee = ffa_dev->dev.driver_data;
457
458	tee_device_unregister(tstee->teedev);
459	tee_shm_pool_free(tstee->pool);
460	kfree(tstee);
461}
462
463static const struct ffa_device_id tstee_device_ids[] = {
464	/* TS RPC protocol UUID: bdcd76d7-825e-4751-963b-86d4f84943ac */
465	{ TS_RPC_UUID },
466	{}
467};
468
469static struct ffa_driver tstee_driver = {
470	.name = "arm_tstee",
471	.probe = tstee_probe,
472	.remove = tstee_remove,
473	.id_table = tstee_device_ids,
474};
475
476module_ffa_driver(tstee_driver);
477
478MODULE_AUTHOR("Balint Dobszay <balint.dobszay@arm.com>");
479MODULE_DESCRIPTION("Arm Trusted Services TEE driver");
480MODULE_LICENSE("GPL");