File Index
Files and directories
Sign in
FILE

call.c

File preview with syntax highlighting.

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