xref: /linux/drivers/tee/qcomtee/call.c (revision 38057e323657695ec8f814aff0cdd1c7e00d3e9b)
1d6e29083SAmirreza Zarrabi // SPDX-License-Identifier: GPL-2.0-only
2d6e29083SAmirreza Zarrabi /*
3d6e29083SAmirreza Zarrabi  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4d6e29083SAmirreza Zarrabi  */
5d6e29083SAmirreza Zarrabi 
6d6e29083SAmirreza Zarrabi #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7d6e29083SAmirreza Zarrabi 
8d6e29083SAmirreza Zarrabi #include <linux/slab.h>
9d6e29083SAmirreza Zarrabi #include <linux/tee.h>
10d6e29083SAmirreza Zarrabi #include <linux/platform_device.h>
11d6e29083SAmirreza Zarrabi #include <linux/xarray.h>
12d6e29083SAmirreza Zarrabi 
13d6e29083SAmirreza Zarrabi #include "qcomtee.h"
14d6e29083SAmirreza Zarrabi 
15d6e29083SAmirreza Zarrabi static int find_qtee_object(struct qcomtee_object **object, unsigned long id,
16d6e29083SAmirreza Zarrabi 			    struct qcomtee_context_data *ctxdata)
17d6e29083SAmirreza Zarrabi {
18d6e29083SAmirreza Zarrabi 	int err = 0;
19d6e29083SAmirreza Zarrabi 
20d6e29083SAmirreza Zarrabi 	guard(rcu)();
21d6e29083SAmirreza Zarrabi 	/* Object release is RCU protected. */
22d6e29083SAmirreza Zarrabi 	*object = idr_find(&ctxdata->qtee_objects_idr, id);
23d6e29083SAmirreza Zarrabi 	if (!qcomtee_object_get(*object))
24d6e29083SAmirreza Zarrabi 		err = -EINVAL;
25d6e29083SAmirreza Zarrabi 
26d6e29083SAmirreza Zarrabi 	return err;
27d6e29083SAmirreza Zarrabi }
28d6e29083SAmirreza Zarrabi 
29d6e29083SAmirreza Zarrabi static void del_qtee_object(unsigned long id,
30d6e29083SAmirreza Zarrabi 			    struct qcomtee_context_data *ctxdata)
31d6e29083SAmirreza Zarrabi {
32d6e29083SAmirreza Zarrabi 	struct qcomtee_object *object;
33d6e29083SAmirreza Zarrabi 
34d6e29083SAmirreza Zarrabi 	scoped_guard(mutex, &ctxdata->qtee_lock)
35d6e29083SAmirreza Zarrabi 		object = idr_remove(&ctxdata->qtee_objects_idr, id);
36d6e29083SAmirreza Zarrabi 
37d6e29083SAmirreza Zarrabi 	qcomtee_object_put(object);
38d6e29083SAmirreza Zarrabi }
39d6e29083SAmirreza Zarrabi 
40d6e29083SAmirreza Zarrabi /**
41d6e29083SAmirreza Zarrabi  * qcomtee_context_add_qtee_object() - Add a QTEE object to the context.
42d6e29083SAmirreza Zarrabi  * @param: TEE parameter representing @object.
43d6e29083SAmirreza Zarrabi  * @object: QTEE object.
44d6e29083SAmirreza Zarrabi  * @ctx: context to add the object.
45d6e29083SAmirreza Zarrabi  *
46d6e29083SAmirreza Zarrabi  * It assumes @object is %QCOMTEE_OBJECT_TYPE_TEE and the caller has already
47d6e29083SAmirreza Zarrabi  * issued qcomtee_object_get() for @object.
48d6e29083SAmirreza Zarrabi  *
49d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
50d6e29083SAmirreza Zarrabi  */
51d6e29083SAmirreza Zarrabi int qcomtee_context_add_qtee_object(struct tee_param *param,
52d6e29083SAmirreza Zarrabi 				    struct qcomtee_object *object,
53d6e29083SAmirreza Zarrabi 				    struct tee_context *ctx)
54d6e29083SAmirreza Zarrabi {
55d6e29083SAmirreza Zarrabi 	int ret;
56d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata = ctx->data;
57d6e29083SAmirreza Zarrabi 
58d6e29083SAmirreza Zarrabi 	scoped_guard(mutex, &ctxdata->qtee_lock)
59d6e29083SAmirreza Zarrabi 		ret = idr_alloc(&ctxdata->qtee_objects_idr, object, 0, 0,
60d6e29083SAmirreza Zarrabi 				GFP_KERNEL);
61d6e29083SAmirreza Zarrabi 	if (ret < 0)
62d6e29083SAmirreza Zarrabi 		return ret;
63d6e29083SAmirreza Zarrabi 
64d6e29083SAmirreza Zarrabi 	param->u.objref.id = ret;
65d6e29083SAmirreza Zarrabi 	/* QTEE Object: QCOMTEE_OBJREF_FLAG_TEE set. */
66d6e29083SAmirreza Zarrabi 	param->u.objref.flags = QCOMTEE_OBJREF_FLAG_TEE;
67d6e29083SAmirreza Zarrabi 
68d6e29083SAmirreza Zarrabi 	return 0;
69d6e29083SAmirreza Zarrabi }
70d6e29083SAmirreza Zarrabi 
71d6e29083SAmirreza Zarrabi /* Retrieve the QTEE object added with qcomtee_context_add_qtee_object(). */
72d6e29083SAmirreza Zarrabi int qcomtee_context_find_qtee_object(struct qcomtee_object **object,
73d6e29083SAmirreza Zarrabi 				     struct tee_param *param,
74d6e29083SAmirreza Zarrabi 				     struct tee_context *ctx)
75d6e29083SAmirreza Zarrabi {
76d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata = ctx->data;
77d6e29083SAmirreza Zarrabi 
78d6e29083SAmirreza Zarrabi 	return find_qtee_object(object, param->u.objref.id, ctxdata);
79d6e29083SAmirreza Zarrabi }
80d6e29083SAmirreza Zarrabi 
81d6e29083SAmirreza Zarrabi /**
82d6e29083SAmirreza Zarrabi  * qcomtee_context_del_qtee_object() - Delete a QTEE object from the context.
83d6e29083SAmirreza Zarrabi  * @param: TEE parameter representing @object.
84d6e29083SAmirreza Zarrabi  * @ctx: context for deleting the object.
85d6e29083SAmirreza Zarrabi  *
86d6e29083SAmirreza Zarrabi  * The @param has been initialized by qcomtee_context_add_qtee_object().
87d6e29083SAmirreza Zarrabi  */
88d6e29083SAmirreza Zarrabi void qcomtee_context_del_qtee_object(struct tee_param *param,
89d6e29083SAmirreza Zarrabi 				     struct tee_context *ctx)
90d6e29083SAmirreza Zarrabi {
91d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata = ctx->data;
92d6e29083SAmirreza Zarrabi 	/* 'qtee_objects_idr' stores QTEE objects only. */
93d6e29083SAmirreza Zarrabi 	if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_TEE)
94d6e29083SAmirreza Zarrabi 		del_qtee_object(param->u.objref.id, ctxdata);
95d6e29083SAmirreza Zarrabi }
96d6e29083SAmirreza Zarrabi 
97d6e29083SAmirreza Zarrabi /**
98d6e29083SAmirreza Zarrabi  * qcomtee_objref_to_arg() - Convert OBJREF parameter to QTEE argument.
99d6e29083SAmirreza Zarrabi  * @arg: QTEE argument.
100d6e29083SAmirreza Zarrabi  * @param: TEE parameter.
101d6e29083SAmirreza Zarrabi  * @ctx: context in which the conversion should happen.
102d6e29083SAmirreza Zarrabi  *
103d6e29083SAmirreza Zarrabi  * It assumes @param is an OBJREF.
104d6e29083SAmirreza Zarrabi  * It does not set @arg.type; the caller should initialize it to a correct
105d6e29083SAmirreza Zarrabi  * &enum qcomtee_arg_type value. It gets the object's refcount in @arg;
106d6e29083SAmirreza Zarrabi  * the caller should manage to put it afterward.
107d6e29083SAmirreza Zarrabi  *
108d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
109d6e29083SAmirreza Zarrabi  */
110d6e29083SAmirreza Zarrabi int qcomtee_objref_to_arg(struct qcomtee_arg *arg, struct tee_param *param,
111d6e29083SAmirreza Zarrabi 			  struct tee_context *ctx)
112d6e29083SAmirreza Zarrabi {
113d6e29083SAmirreza Zarrabi 	int err = -EINVAL;
114d6e29083SAmirreza Zarrabi 
115d6e29083SAmirreza Zarrabi 	arg->o = NULL_QCOMTEE_OBJECT;
116d6e29083SAmirreza Zarrabi 	/* param is a NULL object: */
117d6e29083SAmirreza Zarrabi 	if (param->u.objref.id == TEE_OBJREF_NULL)
118d6e29083SAmirreza Zarrabi 		return 0;
119d6e29083SAmirreza Zarrabi 
120d6e29083SAmirreza Zarrabi 	/* param is a callback object: */
121d6e29083SAmirreza Zarrabi 	if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_USER)
122d6e29083SAmirreza Zarrabi 		err =  qcomtee_user_param_to_object(&arg->o, param, ctx);
123d6e29083SAmirreza Zarrabi 	/* param is a QTEE object: */
124d6e29083SAmirreza Zarrabi 	else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_TEE)
125d6e29083SAmirreza Zarrabi 		err = qcomtee_context_find_qtee_object(&arg->o, param, ctx);
126*87ab676dSAmirreza Zarrabi 	/* param is a memory object: */
127*87ab676dSAmirreza Zarrabi 	else if (param->u.objref.flags & QCOMTEE_OBJREF_FLAG_MEM)
128*87ab676dSAmirreza Zarrabi 		err = qcomtee_memobj_param_to_object(&arg->o, param, ctx);
129d6e29083SAmirreza Zarrabi 
130d6e29083SAmirreza Zarrabi 	/*
131d6e29083SAmirreza Zarrabi 	 * For callback objects, call qcomtee_object_get() to keep a temporary
132d6e29083SAmirreza Zarrabi 	 * copy for the driver, as these objects are released asynchronously
133d6e29083SAmirreza Zarrabi 	 * and may disappear even before returning from QTEE.
134d6e29083SAmirreza Zarrabi 	 *
135d6e29083SAmirreza Zarrabi 	 *  - For direct object invocations, the matching put is called in
136d6e29083SAmirreza Zarrabi 	 *    qcomtee_object_invoke() when parsing the QTEE response.
137d6e29083SAmirreza Zarrabi 	 *  - For callback responses, put is called in qcomtee_user_object_notify()
138d6e29083SAmirreza Zarrabi 	 *    after QTEE has received its copies.
139d6e29083SAmirreza Zarrabi 	 */
140d6e29083SAmirreza Zarrabi 
141d6e29083SAmirreza Zarrabi 	if (!err && (typeof_qcomtee_object(arg->o) == QCOMTEE_OBJECT_TYPE_CB))
142d6e29083SAmirreza Zarrabi 		qcomtee_object_get(arg->o);
143d6e29083SAmirreza Zarrabi 
144d6e29083SAmirreza Zarrabi 	return err;
145d6e29083SAmirreza Zarrabi }
146d6e29083SAmirreza Zarrabi 
147d6e29083SAmirreza Zarrabi /**
148d6e29083SAmirreza Zarrabi  * qcomtee_objref_from_arg() - Convert QTEE argument to OBJREF param.
149d6e29083SAmirreza Zarrabi  * @param: TEE parameter.
150d6e29083SAmirreza Zarrabi  * @arg: QTEE argument.
151d6e29083SAmirreza Zarrabi  * @ctx: context in which the conversion should happen.
152d6e29083SAmirreza Zarrabi  *
153d6e29083SAmirreza Zarrabi  * It assumes @arg is of %QCOMTEE_ARG_TYPE_IO or %QCOMTEE_ARG_TYPE_OO.
154d6e29083SAmirreza Zarrabi  * It does not set @param.attr; the caller should initialize it to a
155d6e29083SAmirreza Zarrabi  * correct type.
156d6e29083SAmirreza Zarrabi  *
157d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
158d6e29083SAmirreza Zarrabi  */
159d6e29083SAmirreza Zarrabi int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *arg,
160d6e29083SAmirreza Zarrabi 			    struct tee_context *ctx)
161d6e29083SAmirreza Zarrabi {
162d6e29083SAmirreza Zarrabi 	struct qcomtee_object *object = arg->o;
163d6e29083SAmirreza Zarrabi 
164d6e29083SAmirreza Zarrabi 	switch (typeof_qcomtee_object(object)) {
165d6e29083SAmirreza Zarrabi 	case QCOMTEE_OBJECT_TYPE_NULL:
166d6e29083SAmirreza Zarrabi 		param->u.objref.id = TEE_OBJREF_NULL;
167d6e29083SAmirreza Zarrabi 
168d6e29083SAmirreza Zarrabi 		return 0;
169d6e29083SAmirreza Zarrabi 	case QCOMTEE_OBJECT_TYPE_CB:
170d6e29083SAmirreza Zarrabi 		/* object is a callback object: */
171d6e29083SAmirreza Zarrabi 		if (is_qcomtee_user_object(object))
172d6e29083SAmirreza Zarrabi 			return qcomtee_user_param_from_object(param, object,
173d6e29083SAmirreza Zarrabi 							      ctx);
174*87ab676dSAmirreza Zarrabi 		/* object is a memory object: */
175*87ab676dSAmirreza Zarrabi 		else if (is_qcomtee_memobj_object(object))
176*87ab676dSAmirreza Zarrabi 			return qcomtee_memobj_param_from_object(param, object,
177*87ab676dSAmirreza Zarrabi 							       ctx);
178d6e29083SAmirreza Zarrabi 
179d6e29083SAmirreza Zarrabi 		break;
180d6e29083SAmirreza Zarrabi 	case QCOMTEE_OBJECT_TYPE_TEE:
181d6e29083SAmirreza Zarrabi 		return qcomtee_context_add_qtee_object(param, object, ctx);
182d6e29083SAmirreza Zarrabi 
183d6e29083SAmirreza Zarrabi 	case QCOMTEE_OBJECT_TYPE_ROOT:
184d6e29083SAmirreza Zarrabi 	default:
185d6e29083SAmirreza Zarrabi 		break;
186d6e29083SAmirreza Zarrabi 	}
187d6e29083SAmirreza Zarrabi 
188d6e29083SAmirreza Zarrabi 	return -EINVAL;
189d6e29083SAmirreza Zarrabi }
190d6e29083SAmirreza Zarrabi 
191d6e29083SAmirreza Zarrabi /**
192d6e29083SAmirreza Zarrabi  * qcomtee_params_to_args() - Convert TEE parameters to QTEE arguments.
193d6e29083SAmirreza Zarrabi  * @u: QTEE arguments.
194d6e29083SAmirreza Zarrabi  * @params: TEE parameters.
195d6e29083SAmirreza Zarrabi  * @num_params: number of elements in the parameter array.
196d6e29083SAmirreza Zarrabi  * @ctx: context in which the conversion should happen.
197d6e29083SAmirreza Zarrabi  *
198d6e29083SAmirreza Zarrabi  * It assumes @u has at least @num_params + 1 entries and has been initialized
199d6e29083SAmirreza Zarrabi  * with %QCOMTEE_ARG_TYPE_INV as &struct qcomtee_arg.type.
200d6e29083SAmirreza Zarrabi  *
201d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
202d6e29083SAmirreza Zarrabi  */
203d6e29083SAmirreza Zarrabi static int qcomtee_params_to_args(struct qcomtee_arg *u,
204d6e29083SAmirreza Zarrabi 				  struct tee_param *params, int num_params,
205d6e29083SAmirreza Zarrabi 				  struct tee_context *ctx)
206d6e29083SAmirreza Zarrabi {
207d6e29083SAmirreza Zarrabi 	int i;
208d6e29083SAmirreza Zarrabi 
209d6e29083SAmirreza Zarrabi 	for (i = 0; i < num_params; i++) {
210d6e29083SAmirreza Zarrabi 		switch (params[i].attr) {
211d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:
212d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:
213d6e29083SAmirreza Zarrabi 			u[i].flags = QCOMTEE_ARG_FLAGS_UADDR;
214d6e29083SAmirreza Zarrabi 			u[i].b.uaddr = params[i].u.ubuf.uaddr;
215d6e29083SAmirreza Zarrabi 			u[i].b.size = params[i].u.ubuf.size;
216d6e29083SAmirreza Zarrabi 
217d6e29083SAmirreza Zarrabi 			if (params[i].attr ==
218d6e29083SAmirreza Zarrabi 			    TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT)
219d6e29083SAmirreza Zarrabi 				u[i].type = QCOMTEE_ARG_TYPE_IB;
220d6e29083SAmirreza Zarrabi 			else /* TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT */
221d6e29083SAmirreza Zarrabi 				u[i].type = QCOMTEE_ARG_TYPE_OB;
222d6e29083SAmirreza Zarrabi 
223d6e29083SAmirreza Zarrabi 			break;
224d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
225d6e29083SAmirreza Zarrabi 			u[i].type = QCOMTEE_ARG_TYPE_IO;
226d6e29083SAmirreza Zarrabi 			if (qcomtee_objref_to_arg(&u[i], &params[i], ctx))
227d6e29083SAmirreza Zarrabi 				goto out_failed;
228d6e29083SAmirreza Zarrabi 
229d6e29083SAmirreza Zarrabi 			break;
230d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT:
231d6e29083SAmirreza Zarrabi 			u[i].type = QCOMTEE_ARG_TYPE_OO;
232d6e29083SAmirreza Zarrabi 			u[i].o = NULL_QCOMTEE_OBJECT;
233d6e29083SAmirreza Zarrabi 			break;
234d6e29083SAmirreza Zarrabi 		default:
235d6e29083SAmirreza Zarrabi 			goto out_failed;
236d6e29083SAmirreza Zarrabi 		}
237d6e29083SAmirreza Zarrabi 	}
238d6e29083SAmirreza Zarrabi 
239d6e29083SAmirreza Zarrabi 	return 0;
240d6e29083SAmirreza Zarrabi 
241d6e29083SAmirreza Zarrabi out_failed:
242d6e29083SAmirreza Zarrabi 	/* Undo qcomtee_objref_to_arg(). */
243d6e29083SAmirreza Zarrabi 	for (i--; i >= 0; i--) {
244d6e29083SAmirreza Zarrabi 		if (u[i].type != QCOMTEE_ARG_TYPE_IO)
245d6e29083SAmirreza Zarrabi 			continue;
246d6e29083SAmirreza Zarrabi 
247d6e29083SAmirreza Zarrabi 		qcomtee_user_object_set_notify(u[i].o, false);
248d6e29083SAmirreza Zarrabi 		/* See docs for qcomtee_objref_to_arg() for double put. */
249d6e29083SAmirreza Zarrabi 		if (typeof_qcomtee_object(u[i].o) == QCOMTEE_OBJECT_TYPE_CB)
250d6e29083SAmirreza Zarrabi 			qcomtee_object_put(u[i].o);
251d6e29083SAmirreza Zarrabi 
252d6e29083SAmirreza Zarrabi 		qcomtee_object_put(u[i].o);
253d6e29083SAmirreza Zarrabi 	}
254d6e29083SAmirreza Zarrabi 
255d6e29083SAmirreza Zarrabi 	return -EINVAL;
256d6e29083SAmirreza Zarrabi }
257d6e29083SAmirreza Zarrabi 
258d6e29083SAmirreza Zarrabi /**
259d6e29083SAmirreza Zarrabi  * qcomtee_params_from_args() - Convert QTEE arguments to TEE parameters.
260d6e29083SAmirreza Zarrabi  * @params: TEE parameters.
261d6e29083SAmirreza Zarrabi  * @u: QTEE arguments.
262d6e29083SAmirreza Zarrabi  * @num_params: number of elements in the parameter array.
263d6e29083SAmirreza Zarrabi  * @ctx: context in which the conversion should happen.
264d6e29083SAmirreza Zarrabi  *
265d6e29083SAmirreza Zarrabi  * @u should have already been initialized by qcomtee_params_to_args().
266d6e29083SAmirreza Zarrabi  * This also represents the end of a QTEE invocation that started with
267d6e29083SAmirreza Zarrabi  * qcomtee_params_to_args() by releasing %QCOMTEE_ARG_TYPE_IO objects.
268d6e29083SAmirreza Zarrabi  *
269d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
270d6e29083SAmirreza Zarrabi  */
271d6e29083SAmirreza Zarrabi static int qcomtee_params_from_args(struct tee_param *params,
272d6e29083SAmirreza Zarrabi 				    struct qcomtee_arg *u, int num_params,
273d6e29083SAmirreza Zarrabi 				    struct tee_context *ctx)
274d6e29083SAmirreza Zarrabi {
275d6e29083SAmirreza Zarrabi 	int i, np;
276d6e29083SAmirreza Zarrabi 
277d6e29083SAmirreza Zarrabi 	qcomtee_arg_for_each(np, u) {
278d6e29083SAmirreza Zarrabi 		switch (u[np].type) {
279d6e29083SAmirreza Zarrabi 		case QCOMTEE_ARG_TYPE_OB:
280d6e29083SAmirreza Zarrabi 			/* TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT */
281d6e29083SAmirreza Zarrabi 			params[np].u.ubuf.size = u[np].b.size;
282d6e29083SAmirreza Zarrabi 
283d6e29083SAmirreza Zarrabi 			break;
284d6e29083SAmirreza Zarrabi 		case QCOMTEE_ARG_TYPE_IO:
285d6e29083SAmirreza Zarrabi 			/* IEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT */
286d6e29083SAmirreza Zarrabi 			qcomtee_object_put(u[np].o);
287d6e29083SAmirreza Zarrabi 
288d6e29083SAmirreza Zarrabi 			break;
289d6e29083SAmirreza Zarrabi 		case QCOMTEE_ARG_TYPE_OO:
290d6e29083SAmirreza Zarrabi 			/* TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT */
291d6e29083SAmirreza Zarrabi 			if (qcomtee_objref_from_arg(&params[np], &u[np], ctx))
292d6e29083SAmirreza Zarrabi 				goto out_failed;
293d6e29083SAmirreza Zarrabi 
294d6e29083SAmirreza Zarrabi 			break;
295d6e29083SAmirreza Zarrabi 		case QCOMTEE_ARG_TYPE_IB:
296d6e29083SAmirreza Zarrabi 		default:
297d6e29083SAmirreza Zarrabi 			break;
298d6e29083SAmirreza Zarrabi 		}
299d6e29083SAmirreza Zarrabi 	}
300d6e29083SAmirreza Zarrabi 
301d6e29083SAmirreza Zarrabi 	return 0;
302d6e29083SAmirreza Zarrabi 
303d6e29083SAmirreza Zarrabi out_failed:
304d6e29083SAmirreza Zarrabi 	/* Undo qcomtee_objref_from_arg(). */
305d6e29083SAmirreza Zarrabi 	for (i = 0; i < np; i++) {
306d6e29083SAmirreza Zarrabi 		if (params[i].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT)
307d6e29083SAmirreza Zarrabi 			qcomtee_context_del_qtee_object(&params[i], ctx);
308d6e29083SAmirreza Zarrabi 	}
309d6e29083SAmirreza Zarrabi 
310d6e29083SAmirreza Zarrabi 	/* Release any IO and OO objects not processed. */
311d6e29083SAmirreza Zarrabi 	for (; u[i].type && i < num_params; i++) {
312d6e29083SAmirreza Zarrabi 		if (u[i].type == QCOMTEE_ARG_TYPE_OO ||
313d6e29083SAmirreza Zarrabi 		    u[i].type == QCOMTEE_ARG_TYPE_IO)
314d6e29083SAmirreza Zarrabi 			qcomtee_object_put(u[i].o);
315d6e29083SAmirreza Zarrabi 	}
316d6e29083SAmirreza Zarrabi 
317d6e29083SAmirreza Zarrabi 	return -EINVAL;
318d6e29083SAmirreza Zarrabi }
319d6e29083SAmirreza Zarrabi 
320d6e29083SAmirreza Zarrabi /* TEE Device Ops. */
321d6e29083SAmirreza Zarrabi 
322d6e29083SAmirreza Zarrabi static int qcomtee_params_check(struct tee_param *params, int num_params)
323d6e29083SAmirreza Zarrabi {
324d6e29083SAmirreza Zarrabi 	int io = 0, oo = 0, ib = 0, ob = 0;
325d6e29083SAmirreza Zarrabi 	int i;
326d6e29083SAmirreza Zarrabi 
327d6e29083SAmirreza Zarrabi 	/* QTEE can accept 64 arguments. */
328d6e29083SAmirreza Zarrabi 	if (num_params > QCOMTEE_ARGS_MAX)
329d6e29083SAmirreza Zarrabi 		return -EINVAL;
330d6e29083SAmirreza Zarrabi 
331d6e29083SAmirreza Zarrabi 	/* Supported parameter types. */
332d6e29083SAmirreza Zarrabi 	for (i = 0; i < num_params; i++) {
333d6e29083SAmirreza Zarrabi 		switch (params[i].attr) {
334d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT:
335d6e29083SAmirreza Zarrabi 			ib++;
336d6e29083SAmirreza Zarrabi 			break;
337d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_OUTPUT:
338d6e29083SAmirreza Zarrabi 			ob++;
339d6e29083SAmirreza Zarrabi 			break;
340d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT:
341d6e29083SAmirreza Zarrabi 			io++;
342d6e29083SAmirreza Zarrabi 			break;
343d6e29083SAmirreza Zarrabi 		case TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT:
344d6e29083SAmirreza Zarrabi 			oo++;
345d6e29083SAmirreza Zarrabi 			break;
346d6e29083SAmirreza Zarrabi 		default:
347d6e29083SAmirreza Zarrabi 			return -EINVAL;
348d6e29083SAmirreza Zarrabi 		}
349d6e29083SAmirreza Zarrabi 	}
350d6e29083SAmirreza Zarrabi 
351d6e29083SAmirreza Zarrabi 	/*  QTEE can accept 16 arguments of each supported types. */
352d6e29083SAmirreza Zarrabi 	if (io > QCOMTEE_ARGS_PER_TYPE || oo > QCOMTEE_ARGS_PER_TYPE ||
353d6e29083SAmirreza Zarrabi 	    ib > QCOMTEE_ARGS_PER_TYPE || ob > QCOMTEE_ARGS_PER_TYPE)
354d6e29083SAmirreza Zarrabi 		return -EINVAL;
355d6e29083SAmirreza Zarrabi 
356d6e29083SAmirreza Zarrabi 	return 0;
357d6e29083SAmirreza Zarrabi }
358d6e29083SAmirreza Zarrabi 
359d6e29083SAmirreza Zarrabi /* Check if an operation on ROOT_QCOMTEE_OBJECT from userspace is permitted. */
360d6e29083SAmirreza Zarrabi static int qcomtee_root_object_check(u32 op, struct tee_param *params,
361d6e29083SAmirreza Zarrabi 				     int num_params)
362d6e29083SAmirreza Zarrabi {
363d6e29083SAmirreza Zarrabi 	/* Some privileged operations recognized by QTEE. */
364d6e29083SAmirreza Zarrabi 	if (op == QCOMTEE_ROOT_OP_NOTIFY_DOMAIN_CHANGE ||
365d6e29083SAmirreza Zarrabi 	    op == QCOMTEE_ROOT_OP_ADCI_ACCEPT ||
366d6e29083SAmirreza Zarrabi 	    op == QCOMTEE_ROOT_OP_ADCI_SHUTDOWN)
367d6e29083SAmirreza Zarrabi 		return -EINVAL;
368d6e29083SAmirreza Zarrabi 
369d6e29083SAmirreza Zarrabi 	/*
370d6e29083SAmirreza Zarrabi 	 * QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS is to register with QTEE
371d6e29083SAmirreza Zarrabi 	 * by passing a credential object as input OBJREF. TEE_OBJREF_NULL as a
372d6e29083SAmirreza Zarrabi 	 * credential object represents a privileged client for QTEE and
373d6e29083SAmirreza Zarrabi 	 * is used by the kernel only.
374d6e29083SAmirreza Zarrabi 	 */
375d6e29083SAmirreza Zarrabi 	if (op == QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS && num_params == 2) {
376d6e29083SAmirreza Zarrabi 		if (params[0].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_INPUT &&
377d6e29083SAmirreza Zarrabi 		    params[1].attr == TEE_IOCTL_PARAM_ATTR_TYPE_OBJREF_OUTPUT) {
378d6e29083SAmirreza Zarrabi 			if (params[0].u.objref.id == TEE_OBJREF_NULL)
379d6e29083SAmirreza Zarrabi 				return -EINVAL;
380d6e29083SAmirreza Zarrabi 		}
381d6e29083SAmirreza Zarrabi 	}
382d6e29083SAmirreza Zarrabi 
383d6e29083SAmirreza Zarrabi 	return 0;
384d6e29083SAmirreza Zarrabi }
385d6e29083SAmirreza Zarrabi 
386d6e29083SAmirreza Zarrabi /**
387d6e29083SAmirreza Zarrabi  * qcomtee_object_invoke() - Invoke a QTEE object.
388d6e29083SAmirreza Zarrabi  * @ctx: TEE context.
389d6e29083SAmirreza Zarrabi  * @arg: ioctl arguments.
390d6e29083SAmirreza Zarrabi  * @params: parameters for the object.
391d6e29083SAmirreza Zarrabi  *
392d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
393d6e29083SAmirreza Zarrabi  */
394d6e29083SAmirreza Zarrabi static int qcomtee_object_invoke(struct tee_context *ctx,
395d6e29083SAmirreza Zarrabi 				 struct tee_ioctl_object_invoke_arg *arg,
396d6e29083SAmirreza Zarrabi 				 struct tee_param *params)
397d6e29083SAmirreza Zarrabi {
398d6e29083SAmirreza Zarrabi 	struct qcomtee_object_invoke_ctx *oic __free(kfree) = NULL;
399d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata = ctx->data;
400d6e29083SAmirreza Zarrabi 	struct qcomtee_arg *u __free(kfree) = NULL;
401d6e29083SAmirreza Zarrabi 	struct qcomtee_object *object;
402d6e29083SAmirreza Zarrabi 	int i, ret, result;
403d6e29083SAmirreza Zarrabi 
404d6e29083SAmirreza Zarrabi 	if (qcomtee_params_check(params, arg->num_params))
405d6e29083SAmirreza Zarrabi 		return -EINVAL;
406d6e29083SAmirreza Zarrabi 
407d6e29083SAmirreza Zarrabi 	/* First, handle reserved operations: */
408d6e29083SAmirreza Zarrabi 	if (arg->op == QCOMTEE_MSG_OBJECT_OP_RELEASE) {
409d6e29083SAmirreza Zarrabi 		del_qtee_object(arg->id, ctxdata);
410d6e29083SAmirreza Zarrabi 
411d6e29083SAmirreza Zarrabi 		return 0;
412d6e29083SAmirreza Zarrabi 	}
413d6e29083SAmirreza Zarrabi 
414d6e29083SAmirreza Zarrabi 	/* Otherwise, invoke a QTEE object: */
415d6e29083SAmirreza Zarrabi 	oic = qcomtee_object_invoke_ctx_alloc(ctx);
416d6e29083SAmirreza Zarrabi 	if (!oic)
417d6e29083SAmirreza Zarrabi 		return -ENOMEM;
418d6e29083SAmirreza Zarrabi 
419d6e29083SAmirreza Zarrabi 	/* +1 for ending QCOMTEE_ARG_TYPE_INV. */
420d6e29083SAmirreza Zarrabi 	u = kcalloc(arg->num_params + 1, sizeof(*u), GFP_KERNEL);
421d6e29083SAmirreza Zarrabi 	if (!u)
422d6e29083SAmirreza Zarrabi 		return -ENOMEM;
423d6e29083SAmirreza Zarrabi 
424d6e29083SAmirreza Zarrabi 	/* Get an object to invoke. */
425d6e29083SAmirreza Zarrabi 	if (arg->id == TEE_OBJREF_NULL) {
426d6e29083SAmirreza Zarrabi 		/* Use ROOT if TEE_OBJREF_NULL is invoked. */
427d6e29083SAmirreza Zarrabi 		if (qcomtee_root_object_check(arg->op, params, arg->num_params))
428d6e29083SAmirreza Zarrabi 			return -EINVAL;
429d6e29083SAmirreza Zarrabi 
430d6e29083SAmirreza Zarrabi 		object = ROOT_QCOMTEE_OBJECT;
431d6e29083SAmirreza Zarrabi 	} else if (find_qtee_object(&object, arg->id, ctxdata)) {
432d6e29083SAmirreza Zarrabi 		return -EINVAL;
433d6e29083SAmirreza Zarrabi 	}
434d6e29083SAmirreza Zarrabi 
435d6e29083SAmirreza Zarrabi 	ret = qcomtee_params_to_args(u, params, arg->num_params, ctx);
436d6e29083SAmirreza Zarrabi 	if (ret)
437d6e29083SAmirreza Zarrabi 		goto out;
438d6e29083SAmirreza Zarrabi 
439d6e29083SAmirreza Zarrabi 	ret = qcomtee_object_do_invoke(oic, object, arg->op, u, &result);
440d6e29083SAmirreza Zarrabi 	if (ret) {
441d6e29083SAmirreza Zarrabi 		qcomtee_arg_for_each_input_object(i, u) {
442d6e29083SAmirreza Zarrabi 			qcomtee_user_object_set_notify(u[i].o, false);
443d6e29083SAmirreza Zarrabi 			qcomtee_object_put(u[i].o);
444d6e29083SAmirreza Zarrabi 		}
445d6e29083SAmirreza Zarrabi 
446d6e29083SAmirreza Zarrabi 		goto out;
447d6e29083SAmirreza Zarrabi 	}
448d6e29083SAmirreza Zarrabi 
449d6e29083SAmirreza Zarrabi 	/* Prase QTEE response and put driver's object copies: */
450d6e29083SAmirreza Zarrabi 
451d6e29083SAmirreza Zarrabi 	if (!result) {
452d6e29083SAmirreza Zarrabi 		/* Assume service is UNAVAIL if unable to process the result. */
453d6e29083SAmirreza Zarrabi 		if (qcomtee_params_from_args(params, u, arg->num_params, ctx))
454d6e29083SAmirreza Zarrabi 			result = QCOMTEE_MSG_ERROR_UNAVAIL;
455d6e29083SAmirreza Zarrabi 	} else {
456d6e29083SAmirreza Zarrabi 		/*
457d6e29083SAmirreza Zarrabi 		 * qcomtee_params_to_args() gets a copy of IO for the driver to
458d6e29083SAmirreza Zarrabi 		 * make sure they do not get released while in the middle of
459d6e29083SAmirreza Zarrabi 		 * invocation. On success (!result), qcomtee_params_from_args()
460d6e29083SAmirreza Zarrabi 		 * puts them; Otherwise, put them here.
461d6e29083SAmirreza Zarrabi 		 */
462d6e29083SAmirreza Zarrabi 		qcomtee_arg_for_each_input_object(i, u)
463d6e29083SAmirreza Zarrabi 			qcomtee_object_put(u[i].o);
464d6e29083SAmirreza Zarrabi 	}
465d6e29083SAmirreza Zarrabi 
466d6e29083SAmirreza Zarrabi 	arg->ret = result;
467d6e29083SAmirreza Zarrabi out:
468d6e29083SAmirreza Zarrabi 	qcomtee_object_put(object);
469d6e29083SAmirreza Zarrabi 
470d6e29083SAmirreza Zarrabi 	return ret;
471d6e29083SAmirreza Zarrabi }
472d6e29083SAmirreza Zarrabi 
473d6e29083SAmirreza Zarrabi /**
474d6e29083SAmirreza Zarrabi  * qcomtee_supp_recv() - Wait for a request for the supplicant.
475d6e29083SAmirreza Zarrabi  * @ctx: TEE context.
476d6e29083SAmirreza Zarrabi  * @op: requested operation on the object.
477d6e29083SAmirreza Zarrabi  * @num_params: number of elements in the parameter array.
478d6e29083SAmirreza Zarrabi  * @params: parameters for @op.
479d6e29083SAmirreza Zarrabi  *
480d6e29083SAmirreza Zarrabi  * The first parameter is a meta %TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT.
481d6e29083SAmirreza Zarrabi  * On input, it provides a user buffer. This buffer is used for parameters of
482d6e29083SAmirreza Zarrabi  * type %TEE_IOCTL_PARAM_ATTR_TYPE_UBUF_INPUT in qcomtee_cb_params_from_args().
483d6e29083SAmirreza Zarrabi  * On output, the object ID and request ID are stored in the meta parameter.
484d6e29083SAmirreza Zarrabi  *
485d6e29083SAmirreza Zarrabi  * @num_params is updated to the number of parameters that actually exist
486d6e29083SAmirreza Zarrabi  * in @params on return.
487d6e29083SAmirreza Zarrabi  *
488d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
489d6e29083SAmirreza Zarrabi  */
490d6e29083SAmirreza Zarrabi static int qcomtee_supp_recv(struct tee_context *ctx, u32 *op, u32 *num_params,
491d6e29083SAmirreza Zarrabi 			     struct tee_param *params)
492d6e29083SAmirreza Zarrabi {
493d6e29083SAmirreza Zarrabi 	struct qcomtee_user_object_request_data data;
494d6e29083SAmirreza Zarrabi 	void __user *uaddr;
495d6e29083SAmirreza Zarrabi 	size_t ubuf_size;
496d6e29083SAmirreza Zarrabi 	int i, ret;
497d6e29083SAmirreza Zarrabi 
498d6e29083SAmirreza Zarrabi 	if (!*num_params)
499d6e29083SAmirreza Zarrabi 		return -EINVAL;
500d6e29083SAmirreza Zarrabi 
501d6e29083SAmirreza Zarrabi 	/* First parameter should be an INOUT + meta parameter. */
502d6e29083SAmirreza Zarrabi 	if (params->attr !=
503d6e29083SAmirreza Zarrabi 	    (TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT | TEE_IOCTL_PARAM_ATTR_META))
504d6e29083SAmirreza Zarrabi 		return -EINVAL;
505d6e29083SAmirreza Zarrabi 
506d6e29083SAmirreza Zarrabi 	/* Other parameters are none. */
507d6e29083SAmirreza Zarrabi 	for (i = 1; i < *num_params; i++)
508d6e29083SAmirreza Zarrabi 		if (params[i].attr)
509d6e29083SAmirreza Zarrabi 			return -EINVAL;
510d6e29083SAmirreza Zarrabi 
511d6e29083SAmirreza Zarrabi 	if (!IS_ALIGNED(params->u.value.a, 8))
512d6e29083SAmirreza Zarrabi 		return -EINVAL;
513d6e29083SAmirreza Zarrabi 
514d6e29083SAmirreza Zarrabi 	/* User buffer and size from meta parameter. */
515d6e29083SAmirreza Zarrabi 	uaddr = u64_to_user_ptr(params->u.value.a);
516d6e29083SAmirreza Zarrabi 	ubuf_size = params->u.value.b;
517d6e29083SAmirreza Zarrabi 	/* Process TEE parameters. +/-1 to ignore the meta parameter. */
518d6e29083SAmirreza Zarrabi 	ret = qcomtee_user_object_select(ctx, params + 1, *num_params - 1,
519d6e29083SAmirreza Zarrabi 					 uaddr, ubuf_size, &data);
520d6e29083SAmirreza Zarrabi 	if (ret)
521d6e29083SAmirreza Zarrabi 		return ret;
522d6e29083SAmirreza Zarrabi 
523d6e29083SAmirreza Zarrabi 	params->u.value.a = data.object_id;
524d6e29083SAmirreza Zarrabi 	params->u.value.b = data.id;
525d6e29083SAmirreza Zarrabi 	params->u.value.c = 0;
526d6e29083SAmirreza Zarrabi 	*op = data.op;
527d6e29083SAmirreza Zarrabi 	*num_params = data.np + 1;
528d6e29083SAmirreza Zarrabi 
529d6e29083SAmirreza Zarrabi 	return 0;
530d6e29083SAmirreza Zarrabi }
531d6e29083SAmirreza Zarrabi 
532d6e29083SAmirreza Zarrabi /**
533d6e29083SAmirreza Zarrabi  * qcomtee_supp_send() - Submit a response for a request.
534d6e29083SAmirreza Zarrabi  * @ctx: TEE context.
535d6e29083SAmirreza Zarrabi  * @errno: return value for the request.
536d6e29083SAmirreza Zarrabi  * @num_params: number of elements in the parameter array.
537d6e29083SAmirreza Zarrabi  * @params: returned parameters.
538d6e29083SAmirreza Zarrabi  *
539d6e29083SAmirreza Zarrabi  * The first parameter is a meta %TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT.
540d6e29083SAmirreza Zarrabi  * It specifies the request ID this response belongs to.
541d6e29083SAmirreza Zarrabi  *
542d6e29083SAmirreza Zarrabi  * Return: On success, returns 0; on failure, returns < 0.
543d6e29083SAmirreza Zarrabi  */
544d6e29083SAmirreza Zarrabi static int qcomtee_supp_send(struct tee_context *ctx, u32 errno, u32 num_params,
545d6e29083SAmirreza Zarrabi 			     struct tee_param *params)
546d6e29083SAmirreza Zarrabi {
547d6e29083SAmirreza Zarrabi 	int req_id;
548d6e29083SAmirreza Zarrabi 
549d6e29083SAmirreza Zarrabi 	if (!num_params)
550d6e29083SAmirreza Zarrabi 		return -EINVAL;
551d6e29083SAmirreza Zarrabi 
552d6e29083SAmirreza Zarrabi 	/* First parameter should be an OUTPUT + meta parameter. */
553d6e29083SAmirreza Zarrabi 	if (params->attr != (TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT |
554d6e29083SAmirreza Zarrabi 			     TEE_IOCTL_PARAM_ATTR_META))
555d6e29083SAmirreza Zarrabi 		return -EINVAL;
556d6e29083SAmirreza Zarrabi 
557d6e29083SAmirreza Zarrabi 	req_id = params->u.value.a;
558d6e29083SAmirreza Zarrabi 	/* Process TEE parameters. +/-1 to ignore the meta parameter. */
559d6e29083SAmirreza Zarrabi 	return qcomtee_user_object_submit(ctx, params + 1, num_params - 1,
560d6e29083SAmirreza Zarrabi 					  req_id, errno);
561d6e29083SAmirreza Zarrabi }
562d6e29083SAmirreza Zarrabi 
563d6e29083SAmirreza Zarrabi static int qcomtee_open(struct tee_context *ctx)
564d6e29083SAmirreza Zarrabi {
565d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata __free(kfree) = NULL;
566d6e29083SAmirreza Zarrabi 
567d6e29083SAmirreza Zarrabi 	ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
568d6e29083SAmirreza Zarrabi 	if (!ctxdata)
569d6e29083SAmirreza Zarrabi 		return -ENOMEM;
570d6e29083SAmirreza Zarrabi 
571d6e29083SAmirreza Zarrabi 	/*
572d6e29083SAmirreza Zarrabi 	 * In the QTEE driver, the same context is used to refcount resources
573d6e29083SAmirreza Zarrabi 	 * shared by QTEE. For example, teedev_ctx_get() is called for any
574d6e29083SAmirreza Zarrabi 	 * instance of callback objects (see qcomtee_user_param_to_object()).
575d6e29083SAmirreza Zarrabi 	 *
576d6e29083SAmirreza Zarrabi 	 * Maintain a copy of teedev for QTEE as it serves as a direct user of
577d6e29083SAmirreza Zarrabi 	 * this context. The teedev will be released in the context's release().
578d6e29083SAmirreza Zarrabi 	 *
579d6e29083SAmirreza Zarrabi 	 * tee_device_unregister() will remain blocked until all contexts
580d6e29083SAmirreza Zarrabi 	 * are released. This includes contexts owned by the user, which are
581d6e29083SAmirreza Zarrabi 	 * closed by teedev_close_context(), as well as those owned by QTEE
582d6e29083SAmirreza Zarrabi 	 * closed by teedev_ctx_put() in object's release().
583d6e29083SAmirreza Zarrabi 	 */
584d6e29083SAmirreza Zarrabi 	if (!tee_device_get(ctx->teedev))
585d6e29083SAmirreza Zarrabi 		return -EINVAL;
586d6e29083SAmirreza Zarrabi 
587d6e29083SAmirreza Zarrabi 	idr_init(&ctxdata->qtee_objects_idr);
588d6e29083SAmirreza Zarrabi 	mutex_init(&ctxdata->qtee_lock);
589d6e29083SAmirreza Zarrabi 	idr_init(&ctxdata->reqs_idr);
590d6e29083SAmirreza Zarrabi 	INIT_LIST_HEAD(&ctxdata->reqs_list);
591d6e29083SAmirreza Zarrabi 	mutex_init(&ctxdata->reqs_lock);
592d6e29083SAmirreza Zarrabi 	init_completion(&ctxdata->req_c);
593d6e29083SAmirreza Zarrabi 
594d6e29083SAmirreza Zarrabi 	ctx->data = no_free_ptr(ctxdata);
595d6e29083SAmirreza Zarrabi 
596d6e29083SAmirreza Zarrabi 	return 0;
597d6e29083SAmirreza Zarrabi }
598d6e29083SAmirreza Zarrabi 
599d6e29083SAmirreza Zarrabi /* Gets called when the user closes the device */
600d6e29083SAmirreza Zarrabi static void qcomtee_close_context(struct tee_context *ctx)
601d6e29083SAmirreza Zarrabi {
602d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata = ctx->data;
603d6e29083SAmirreza Zarrabi 	struct qcomtee_object *object;
604d6e29083SAmirreza Zarrabi 	int id;
605d6e29083SAmirreza Zarrabi 
606d6e29083SAmirreza Zarrabi 	/* Process QUEUED or PROCESSING requests. */
607d6e29083SAmirreza Zarrabi 	qcomtee_requests_destroy(ctxdata);
608d6e29083SAmirreza Zarrabi 	/* Release QTEE objects. */
609d6e29083SAmirreza Zarrabi 	idr_for_each_entry(&ctxdata->qtee_objects_idr, object, id)
610d6e29083SAmirreza Zarrabi 		qcomtee_object_put(object);
611d6e29083SAmirreza Zarrabi }
612d6e29083SAmirreza Zarrabi 
613d6e29083SAmirreza Zarrabi /* Gets called when the final reference to the context goes away. */
614d6e29083SAmirreza Zarrabi static void qcomtee_release(struct tee_context *ctx)
615d6e29083SAmirreza Zarrabi {
616d6e29083SAmirreza Zarrabi 	struct qcomtee_context_data *ctxdata = ctx->data;
617d6e29083SAmirreza Zarrabi 
618d6e29083SAmirreza Zarrabi 	idr_destroy(&ctxdata->qtee_objects_idr);
619d6e29083SAmirreza Zarrabi 	idr_destroy(&ctxdata->reqs_idr);
620d6e29083SAmirreza Zarrabi 	kfree(ctxdata);
621d6e29083SAmirreza Zarrabi 
622d6e29083SAmirreza Zarrabi 	/* There is nothing shared in this context with QTEE. */
623d6e29083SAmirreza Zarrabi 	tee_device_put(ctx->teedev);
624d6e29083SAmirreza Zarrabi }
625d6e29083SAmirreza Zarrabi 
626d6e29083SAmirreza Zarrabi static void qcomtee_get_version(struct tee_device *teedev,
627d6e29083SAmirreza Zarrabi 				struct tee_ioctl_version_data *vers)
628d6e29083SAmirreza Zarrabi {
629d6e29083SAmirreza Zarrabi 	struct tee_ioctl_version_data v = {
630d6e29083SAmirreza Zarrabi 		.impl_id = TEE_IMPL_ID_QTEE,
631d6e29083SAmirreza Zarrabi 		.gen_caps = TEE_GEN_CAP_OBJREF,
632d6e29083SAmirreza Zarrabi 	};
633d6e29083SAmirreza Zarrabi 
634d6e29083SAmirreza Zarrabi 	*vers = v;
635d6e29083SAmirreza Zarrabi }
636d6e29083SAmirreza Zarrabi 
637d6e29083SAmirreza Zarrabi /**
638d6e29083SAmirreza Zarrabi  * qcomtee_get_qtee_feature_list() - Query QTEE features versions.
639d6e29083SAmirreza Zarrabi  * @ctx: TEE context.
640d6e29083SAmirreza Zarrabi  * @id: ID of the feature to query.
641d6e29083SAmirreza Zarrabi  * @version: version of the feature.
642d6e29083SAmirreza Zarrabi  *
643d6e29083SAmirreza Zarrabi  * Used to query the verion of features supported by QTEE.
644d6e29083SAmirreza Zarrabi  */
645d6e29083SAmirreza Zarrabi static void qcomtee_get_qtee_feature_list(struct tee_context *ctx, u32 id,
646d6e29083SAmirreza Zarrabi 					  u32 *version)
647d6e29083SAmirreza Zarrabi {
648d6e29083SAmirreza Zarrabi 	struct qcomtee_object_invoke_ctx *oic __free(kfree);
649d6e29083SAmirreza Zarrabi 	struct qcomtee_object *client_env, *service;
650d6e29083SAmirreza Zarrabi 	struct qcomtee_arg u[3] = { 0 };
651d6e29083SAmirreza Zarrabi 	int result;
652d6e29083SAmirreza Zarrabi 
653d6e29083SAmirreza Zarrabi 	oic = qcomtee_object_invoke_ctx_alloc(ctx);
654d6e29083SAmirreza Zarrabi 	if (!oic)
655d6e29083SAmirreza Zarrabi 		return;
656d6e29083SAmirreza Zarrabi 
657d6e29083SAmirreza Zarrabi 	client_env = qcomtee_object_get_client_env(oic);
658d6e29083SAmirreza Zarrabi 	if (client_env == NULL_QCOMTEE_OBJECT)
659d6e29083SAmirreza Zarrabi 		return;
660d6e29083SAmirreza Zarrabi 
661d6e29083SAmirreza Zarrabi 	/* Get ''FeatureVersions Service'' object. */
662d6e29083SAmirreza Zarrabi 	service = qcomtee_object_get_service(oic, client_env,
663d6e29083SAmirreza Zarrabi 					     QCOMTEE_FEATURE_VER_UID);
664d6e29083SAmirreza Zarrabi 	if (service == NULL_QCOMTEE_OBJECT)
665d6e29083SAmirreza Zarrabi 		goto out_failed;
666d6e29083SAmirreza Zarrabi 
667d6e29083SAmirreza Zarrabi 	/* IB: Feature to query. */
668d6e29083SAmirreza Zarrabi 	u[0].b.addr = &id;
669d6e29083SAmirreza Zarrabi 	u[0].b.size = sizeof(id);
670d6e29083SAmirreza Zarrabi 	u[0].type = QCOMTEE_ARG_TYPE_IB;
671d6e29083SAmirreza Zarrabi 
672d6e29083SAmirreza Zarrabi 	/* OB: Version returned. */
673d6e29083SAmirreza Zarrabi 	u[1].b.addr = version;
674d6e29083SAmirreza Zarrabi 	u[1].b.size = sizeof(*version);
675d6e29083SAmirreza Zarrabi 	u[1].type = QCOMTEE_ARG_TYPE_OB;
676d6e29083SAmirreza Zarrabi 
677d6e29083SAmirreza Zarrabi 	qcomtee_object_do_invoke(oic, service, QCOMTEE_FEATURE_VER_OP_GET, u,
678d6e29083SAmirreza Zarrabi 				 &result);
679d6e29083SAmirreza Zarrabi 
680d6e29083SAmirreza Zarrabi out_failed:
681d6e29083SAmirreza Zarrabi 	qcomtee_object_put(service);
682d6e29083SAmirreza Zarrabi 	qcomtee_object_put(client_env);
683d6e29083SAmirreza Zarrabi }
684d6e29083SAmirreza Zarrabi 
685d6e29083SAmirreza Zarrabi static const struct tee_driver_ops qcomtee_ops = {
686d6e29083SAmirreza Zarrabi 	.get_version = qcomtee_get_version,
687d6e29083SAmirreza Zarrabi 	.open = qcomtee_open,
688d6e29083SAmirreza Zarrabi 	.close_context = qcomtee_close_context,
689d6e29083SAmirreza Zarrabi 	.release = qcomtee_release,
690d6e29083SAmirreza Zarrabi 	.object_invoke_func = qcomtee_object_invoke,
691d6e29083SAmirreza Zarrabi 	.supp_recv = qcomtee_supp_recv,
692d6e29083SAmirreza Zarrabi 	.supp_send = qcomtee_supp_send,
693d6e29083SAmirreza Zarrabi };
694d6e29083SAmirreza Zarrabi 
695d6e29083SAmirreza Zarrabi static const struct tee_desc qcomtee_desc = {
696d6e29083SAmirreza Zarrabi 	.name = "qcomtee",
697d6e29083SAmirreza Zarrabi 	.ops = &qcomtee_ops,
698d6e29083SAmirreza Zarrabi 	.owner = THIS_MODULE,
699d6e29083SAmirreza Zarrabi };
700d6e29083SAmirreza Zarrabi 
701d6e29083SAmirreza Zarrabi static int qcomtee_probe(struct platform_device *pdev)
702d6e29083SAmirreza Zarrabi {
703d6e29083SAmirreza Zarrabi 	struct workqueue_struct *async_wq;
704d6e29083SAmirreza Zarrabi 	struct tee_device *teedev;
705d6e29083SAmirreza Zarrabi 	struct tee_shm_pool *pool;
706d6e29083SAmirreza Zarrabi 	struct tee_context *ctx;
707d6e29083SAmirreza Zarrabi 	struct qcomtee *qcomtee;
708d6e29083SAmirreza Zarrabi 	int err;
709d6e29083SAmirreza Zarrabi 
710d6e29083SAmirreza Zarrabi 	qcomtee = kzalloc(sizeof(*qcomtee), GFP_KERNEL);
711d6e29083SAmirreza Zarrabi 	if (!qcomtee)
712d6e29083SAmirreza Zarrabi 		return -ENOMEM;
713d6e29083SAmirreza Zarrabi 
714d6e29083SAmirreza Zarrabi 	pool = qcomtee_shm_pool_alloc();
715d6e29083SAmirreza Zarrabi 	if (IS_ERR(pool)) {
716d6e29083SAmirreza Zarrabi 		err = PTR_ERR(pool);
717d6e29083SAmirreza Zarrabi 
718d6e29083SAmirreza Zarrabi 		goto err_free_qcomtee;
719d6e29083SAmirreza Zarrabi 	}
720d6e29083SAmirreza Zarrabi 
721d6e29083SAmirreza Zarrabi 	teedev = tee_device_alloc(&qcomtee_desc, NULL, pool, qcomtee);
722d6e29083SAmirreza Zarrabi 	if (IS_ERR(teedev)) {
723d6e29083SAmirreza Zarrabi 		err = PTR_ERR(teedev);
724d6e29083SAmirreza Zarrabi 
725d6e29083SAmirreza Zarrabi 		goto err_pool_destroy;
726d6e29083SAmirreza Zarrabi 	}
727d6e29083SAmirreza Zarrabi 
728d6e29083SAmirreza Zarrabi 	qcomtee->teedev = teedev;
729d6e29083SAmirreza Zarrabi 	qcomtee->pool = pool;
730d6e29083SAmirreza Zarrabi 	err = tee_device_register(qcomtee->teedev);
731d6e29083SAmirreza Zarrabi 	if (err)
732d6e29083SAmirreza Zarrabi 		goto err_unreg_teedev;
733d6e29083SAmirreza Zarrabi 
734d6e29083SAmirreza Zarrabi 	platform_set_drvdata(pdev, qcomtee);
735d6e29083SAmirreza Zarrabi 	/* Start async wq. */
736d6e29083SAmirreza Zarrabi 	async_wq = alloc_ordered_workqueue("qcomtee_wq", 0);
737d6e29083SAmirreza Zarrabi 	if (!async_wq) {
738d6e29083SAmirreza Zarrabi 		err = -ENOMEM;
739d6e29083SAmirreza Zarrabi 
740d6e29083SAmirreza Zarrabi 		goto err_unreg_teedev;
741d6e29083SAmirreza Zarrabi 	}
742d6e29083SAmirreza Zarrabi 
743d6e29083SAmirreza Zarrabi 	qcomtee->wq = async_wq;
744d6e29083SAmirreza Zarrabi 	/* Driver context used for async operations of teedev. */
745d6e29083SAmirreza Zarrabi 	ctx = teedev_open(qcomtee->teedev);
746d6e29083SAmirreza Zarrabi 	if (IS_ERR(ctx)) {
747d6e29083SAmirreza Zarrabi 		err = PTR_ERR(ctx);
748d6e29083SAmirreza Zarrabi 
749d6e29083SAmirreza Zarrabi 		goto err_dest_wq;
750d6e29083SAmirreza Zarrabi 	}
751d6e29083SAmirreza Zarrabi 
752d6e29083SAmirreza Zarrabi 	qcomtee->ctx = ctx;
753d6e29083SAmirreza Zarrabi 	/* Init Object table. */
754d6e29083SAmirreza Zarrabi 	qcomtee->xa_last_id = 0;
755d6e29083SAmirreza Zarrabi 	xa_init_flags(&qcomtee->xa_local_objects, XA_FLAGS_ALLOC);
756d6e29083SAmirreza Zarrabi 	/* Get QTEE verion. */
757d6e29083SAmirreza Zarrabi 	qcomtee_get_qtee_feature_list(qcomtee->ctx,
758d6e29083SAmirreza Zarrabi 				      QCOMTEE_FEATURE_VER_OP_GET_QTEE_ID,
759d6e29083SAmirreza Zarrabi 				      &qcomtee->qtee_version);
760d6e29083SAmirreza Zarrabi 
761d6e29083SAmirreza Zarrabi 	pr_info("QTEE version %u.%u.%u\n",
762d6e29083SAmirreza Zarrabi 		QTEE_VERSION_GET_MAJOR(qcomtee->qtee_version),
763d6e29083SAmirreza Zarrabi 		QTEE_VERSION_GET_MINOR(qcomtee->qtee_version),
764d6e29083SAmirreza Zarrabi 		QTEE_VERSION_GET_PATCH(qcomtee->qtee_version));
765d6e29083SAmirreza Zarrabi 
766d6e29083SAmirreza Zarrabi 	return 0;
767d6e29083SAmirreza Zarrabi 
768d6e29083SAmirreza Zarrabi err_dest_wq:
769d6e29083SAmirreza Zarrabi 	destroy_workqueue(qcomtee->wq);
770d6e29083SAmirreza Zarrabi err_unreg_teedev:
771d6e29083SAmirreza Zarrabi 	tee_device_unregister(qcomtee->teedev);
772d6e29083SAmirreza Zarrabi err_pool_destroy:
773d6e29083SAmirreza Zarrabi 	tee_shm_pool_free(pool);
774d6e29083SAmirreza Zarrabi err_free_qcomtee:
775d6e29083SAmirreza Zarrabi 	kfree(qcomtee);
776d6e29083SAmirreza Zarrabi 
777d6e29083SAmirreza Zarrabi 	return err;
778d6e29083SAmirreza Zarrabi }
779d6e29083SAmirreza Zarrabi 
780d6e29083SAmirreza Zarrabi /**
781d6e29083SAmirreza Zarrabi  * qcomtee_remove() - Device Removal Routine.
782d6e29083SAmirreza Zarrabi  * @pdev: platform device information struct.
783d6e29083SAmirreza Zarrabi  *
784d6e29083SAmirreza Zarrabi  * It is called by the platform subsystem to alert the driver that it should
785d6e29083SAmirreza Zarrabi  * release the device.
786d6e29083SAmirreza Zarrabi  *
787d6e29083SAmirreza Zarrabi  * QTEE does not provide an API to inform it about a callback object going away.
788d6e29083SAmirreza Zarrabi  * However, when releasing QTEE objects, any callback object sent to QTEE
789d6e29083SAmirreza Zarrabi  * previously would be released by QTEE as part of the object release.
790d6e29083SAmirreza Zarrabi  */
791d6e29083SAmirreza Zarrabi static void qcomtee_remove(struct platform_device *pdev)
792d6e29083SAmirreza Zarrabi {
793d6e29083SAmirreza Zarrabi 	struct qcomtee *qcomtee = platform_get_drvdata(pdev);
794d6e29083SAmirreza Zarrabi 
795d6e29083SAmirreza Zarrabi 	teedev_close_context(qcomtee->ctx);
796d6e29083SAmirreza Zarrabi 	/* Wait for RELEASE operations to be processed for QTEE objects. */
797d6e29083SAmirreza Zarrabi 	tee_device_unregister(qcomtee->teedev);
798d6e29083SAmirreza Zarrabi 	destroy_workqueue(qcomtee->wq);
799d6e29083SAmirreza Zarrabi 	tee_shm_pool_free(qcomtee->pool);
800d6e29083SAmirreza Zarrabi 	kfree(qcomtee);
801d6e29083SAmirreza Zarrabi }
802d6e29083SAmirreza Zarrabi 
803d6e29083SAmirreza Zarrabi static const struct platform_device_id qcomtee_ids[] = { { "qcomtee", 0 }, {} };
804d6e29083SAmirreza Zarrabi MODULE_DEVICE_TABLE(platform, qcomtee_ids);
805d6e29083SAmirreza Zarrabi 
806d6e29083SAmirreza Zarrabi static struct platform_driver qcomtee_platform_driver = {
807d6e29083SAmirreza Zarrabi 	.probe = qcomtee_probe,
808d6e29083SAmirreza Zarrabi 	.remove = qcomtee_remove,
809d6e29083SAmirreza Zarrabi 	.driver = {
810d6e29083SAmirreza Zarrabi 		.name = "qcomtee",
811d6e29083SAmirreza Zarrabi 	},
812d6e29083SAmirreza Zarrabi 	.id_table = qcomtee_ids,
813d6e29083SAmirreza Zarrabi };
814d6e29083SAmirreza Zarrabi 
815d6e29083SAmirreza Zarrabi module_platform_driver(qcomtee_platform_driver);
816d6e29083SAmirreza Zarrabi 
817d6e29083SAmirreza Zarrabi MODULE_AUTHOR("Qualcomm");
818d6e29083SAmirreza Zarrabi MODULE_DESCRIPTION("QTEE driver");
819d6e29083SAmirreza Zarrabi MODULE_VERSION("1.0");
820d6e29083SAmirreza Zarrabi MODULE_LICENSE("GPL");
821