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