xref: /OK3568_Linux_fs/kernel/drivers/tee/optee/core.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2015, Linaro Limited
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/arm-smccc.h>
9*4882a593Smuzhiyun #include <linux/crash_dump.h>
10*4882a593Smuzhiyun #include <linux/errno.h>
11*4882a593Smuzhiyun #include <linux/io.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of.h>
14*4882a593Smuzhiyun #include <linux/of_platform.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun #include <linux/string.h>
18*4882a593Smuzhiyun #include <linux/tee_drv.h>
19*4882a593Smuzhiyun #include <linux/types.h>
20*4882a593Smuzhiyun #include <linux/uaccess.h>
21*4882a593Smuzhiyun #include <linux/workqueue.h>
22*4882a593Smuzhiyun #include "optee_private.h"
23*4882a593Smuzhiyun #include "optee_smc.h"
24*4882a593Smuzhiyun #include "shm_pool.h"
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define DRIVER_NAME "optee"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define OPTEE_SHM_NUM_PRIV_PAGES	CONFIG_OPTEE_SHM_NUM_PRIV_PAGES
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun /**
31*4882a593Smuzhiyun  * optee_from_msg_param() - convert from OPTEE_MSG parameters to
32*4882a593Smuzhiyun  *			    struct tee_param
33*4882a593Smuzhiyun  * @params:	subsystem internal parameter representation
34*4882a593Smuzhiyun  * @num_params:	number of elements in the parameter arrays
35*4882a593Smuzhiyun  * @msg_params:	OPTEE_MSG parameters
36*4882a593Smuzhiyun  * Returns 0 on success or <0 on failure
37*4882a593Smuzhiyun  */
optee_from_msg_param(struct tee_param * params,size_t num_params,const struct optee_msg_param * msg_params)38*4882a593Smuzhiyun int optee_from_msg_param(struct tee_param *params, size_t num_params,
39*4882a593Smuzhiyun 			 const struct optee_msg_param *msg_params)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	int rc;
42*4882a593Smuzhiyun 	size_t n;
43*4882a593Smuzhiyun 	struct tee_shm *shm;
44*4882a593Smuzhiyun 	phys_addr_t pa;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	for (n = 0; n < num_params; n++) {
47*4882a593Smuzhiyun 		struct tee_param *p = params + n;
48*4882a593Smuzhiyun 		const struct optee_msg_param *mp = msg_params + n;
49*4882a593Smuzhiyun 		u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 		switch (attr) {
52*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_NONE:
53*4882a593Smuzhiyun 			p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
54*4882a593Smuzhiyun 			memset(&p->u, 0, sizeof(p->u));
55*4882a593Smuzhiyun 			break;
56*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
57*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
58*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
59*4882a593Smuzhiyun 			p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT +
60*4882a593Smuzhiyun 				  attr - OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
61*4882a593Smuzhiyun 			p->u.value.a = mp->u.value.a;
62*4882a593Smuzhiyun 			p->u.value.b = mp->u.value.b;
63*4882a593Smuzhiyun 			p->u.value.c = mp->u.value.c;
64*4882a593Smuzhiyun 			break;
65*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
66*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
67*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
68*4882a593Smuzhiyun 			p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
69*4882a593Smuzhiyun 				  attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
70*4882a593Smuzhiyun 			p->u.memref.size = mp->u.tmem.size;
71*4882a593Smuzhiyun 			shm = (struct tee_shm *)(unsigned long)
72*4882a593Smuzhiyun 				mp->u.tmem.shm_ref;
73*4882a593Smuzhiyun 			if (!shm) {
74*4882a593Smuzhiyun 				p->u.memref.shm_offs = 0;
75*4882a593Smuzhiyun 				p->u.memref.shm = NULL;
76*4882a593Smuzhiyun 				break;
77*4882a593Smuzhiyun 			}
78*4882a593Smuzhiyun 			rc = tee_shm_get_pa(shm, 0, &pa);
79*4882a593Smuzhiyun 			if (rc)
80*4882a593Smuzhiyun 				return rc;
81*4882a593Smuzhiyun 			p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
82*4882a593Smuzhiyun 			p->u.memref.shm = shm;
83*4882a593Smuzhiyun 			break;
84*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
85*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
86*4882a593Smuzhiyun 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
87*4882a593Smuzhiyun 			p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
88*4882a593Smuzhiyun 				  attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
89*4882a593Smuzhiyun 			p->u.memref.size = mp->u.rmem.size;
90*4882a593Smuzhiyun 			shm = (struct tee_shm *)(unsigned long)
91*4882a593Smuzhiyun 				mp->u.rmem.shm_ref;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 			if (!shm) {
94*4882a593Smuzhiyun 				p->u.memref.shm_offs = 0;
95*4882a593Smuzhiyun 				p->u.memref.shm = NULL;
96*4882a593Smuzhiyun 				break;
97*4882a593Smuzhiyun 			}
98*4882a593Smuzhiyun 			p->u.memref.shm_offs = mp->u.rmem.offs;
99*4882a593Smuzhiyun 			p->u.memref.shm = shm;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 			break;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		default:
104*4882a593Smuzhiyun 			return -EINVAL;
105*4882a593Smuzhiyun 		}
106*4882a593Smuzhiyun 	}
107*4882a593Smuzhiyun 	return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
to_msg_param_tmp_mem(struct optee_msg_param * mp,const struct tee_param * p)110*4882a593Smuzhiyun static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
111*4882a593Smuzhiyun 				const struct tee_param *p)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	int rc;
114*4882a593Smuzhiyun 	phys_addr_t pa;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
117*4882a593Smuzhiyun 		   TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
120*4882a593Smuzhiyun 	mp->u.tmem.size = p->u.memref.size;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	if (!p->u.memref.shm) {
123*4882a593Smuzhiyun 		mp->u.tmem.buf_ptr = 0;
124*4882a593Smuzhiyun 		return 0;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	rc = tee_shm_get_pa(p->u.memref.shm, p->u.memref.shm_offs, &pa);
128*4882a593Smuzhiyun 	if (rc)
129*4882a593Smuzhiyun 		return rc;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	mp->u.tmem.buf_ptr = pa;
132*4882a593Smuzhiyun 	mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
133*4882a593Smuzhiyun 		    OPTEE_MSG_ATTR_CACHE_SHIFT;
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return 0;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
to_msg_param_reg_mem(struct optee_msg_param * mp,const struct tee_param * p)138*4882a593Smuzhiyun static int to_msg_param_reg_mem(struct optee_msg_param *mp,
139*4882a593Smuzhiyun 				const struct tee_param *p)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
142*4882a593Smuzhiyun 		   TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	mp->u.rmem.shm_ref = (unsigned long)p->u.memref.shm;
145*4882a593Smuzhiyun 	mp->u.rmem.size = p->u.memref.size;
146*4882a593Smuzhiyun 	mp->u.rmem.offs = p->u.memref.shm_offs;
147*4882a593Smuzhiyun 	return 0;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /**
151*4882a593Smuzhiyun  * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
152*4882a593Smuzhiyun  * @msg_params:	OPTEE_MSG parameters
153*4882a593Smuzhiyun  * @num_params:	number of elements in the parameter arrays
154*4882a593Smuzhiyun  * @params:	subsystem itnernal parameter representation
155*4882a593Smuzhiyun  * Returns 0 on success or <0 on failure
156*4882a593Smuzhiyun  */
optee_to_msg_param(struct optee_msg_param * msg_params,size_t num_params,const struct tee_param * params)157*4882a593Smuzhiyun int optee_to_msg_param(struct optee_msg_param *msg_params, size_t num_params,
158*4882a593Smuzhiyun 		       const struct tee_param *params)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun 	int rc;
161*4882a593Smuzhiyun 	size_t n;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	for (n = 0; n < num_params; n++) {
164*4882a593Smuzhiyun 		const struct tee_param *p = params + n;
165*4882a593Smuzhiyun 		struct optee_msg_param *mp = msg_params + n;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		switch (p->attr) {
168*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
169*4882a593Smuzhiyun 			mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
170*4882a593Smuzhiyun 			memset(&mp->u, 0, sizeof(mp->u));
171*4882a593Smuzhiyun 			break;
172*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
173*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
174*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
175*4882a593Smuzhiyun 			mp->attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT + p->attr -
176*4882a593Smuzhiyun 				   TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT;
177*4882a593Smuzhiyun 			mp->u.value.a = p->u.value.a;
178*4882a593Smuzhiyun 			mp->u.value.b = p->u.value.b;
179*4882a593Smuzhiyun 			mp->u.value.c = p->u.value.c;
180*4882a593Smuzhiyun 			break;
181*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
182*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
183*4882a593Smuzhiyun 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
184*4882a593Smuzhiyun 			if (tee_shm_is_registered(p->u.memref.shm))
185*4882a593Smuzhiyun 				rc = to_msg_param_reg_mem(mp, p);
186*4882a593Smuzhiyun 			else
187*4882a593Smuzhiyun 				rc = to_msg_param_tmp_mem(mp, p);
188*4882a593Smuzhiyun 			if (rc)
189*4882a593Smuzhiyun 				return rc;
190*4882a593Smuzhiyun 			break;
191*4882a593Smuzhiyun 		default:
192*4882a593Smuzhiyun 			return -EINVAL;
193*4882a593Smuzhiyun 		}
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 	return 0;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun 
optee_get_version(struct tee_device * teedev,struct tee_ioctl_version_data * vers)198*4882a593Smuzhiyun static void optee_get_version(struct tee_device *teedev,
199*4882a593Smuzhiyun 			      struct tee_ioctl_version_data *vers)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct tee_ioctl_version_data v = {
202*4882a593Smuzhiyun 		.impl_id = TEE_IMPL_ID_OPTEE,
203*4882a593Smuzhiyun 		.impl_caps = TEE_OPTEE_CAP_TZ,
204*4882a593Smuzhiyun 		.gen_caps = TEE_GEN_CAP_GP,
205*4882a593Smuzhiyun 	};
206*4882a593Smuzhiyun 	struct optee *optee = tee_get_drvdata(teedev);
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
209*4882a593Smuzhiyun 		v.gen_caps |= TEE_GEN_CAP_REG_MEM;
210*4882a593Smuzhiyun 	if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
211*4882a593Smuzhiyun 		v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
212*4882a593Smuzhiyun 	*vers = v;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun 
optee_bus_scan(struct work_struct * work)215*4882a593Smuzhiyun static void optee_bus_scan(struct work_struct *work)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun 
optee_open(struct tee_context * ctx)220*4882a593Smuzhiyun static int optee_open(struct tee_context *ctx)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun 	struct optee_context_data *ctxdata;
223*4882a593Smuzhiyun 	struct tee_device *teedev = ctx->teedev;
224*4882a593Smuzhiyun 	struct optee *optee = tee_get_drvdata(teedev);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL);
227*4882a593Smuzhiyun 	if (!ctxdata)
228*4882a593Smuzhiyun 		return -ENOMEM;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	if (teedev == optee->supp_teedev) {
231*4882a593Smuzhiyun 		bool busy = true;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 		mutex_lock(&optee->supp.mutex);
234*4882a593Smuzhiyun 		if (!optee->supp.ctx) {
235*4882a593Smuzhiyun 			busy = false;
236*4882a593Smuzhiyun 			optee->supp.ctx = ctx;
237*4882a593Smuzhiyun 		}
238*4882a593Smuzhiyun 		mutex_unlock(&optee->supp.mutex);
239*4882a593Smuzhiyun 		if (busy) {
240*4882a593Smuzhiyun 			kfree(ctxdata);
241*4882a593Smuzhiyun 			return -EBUSY;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 		if (!optee->scan_bus_done) {
245*4882a593Smuzhiyun 			INIT_WORK(&optee->scan_bus_work, optee_bus_scan);
246*4882a593Smuzhiyun 			optee->scan_bus_wq = create_workqueue("optee_bus_scan");
247*4882a593Smuzhiyun 			if (!optee->scan_bus_wq) {
248*4882a593Smuzhiyun 				kfree(ctxdata);
249*4882a593Smuzhiyun 				return -ECHILD;
250*4882a593Smuzhiyun 			}
251*4882a593Smuzhiyun 			queue_work(optee->scan_bus_wq, &optee->scan_bus_work);
252*4882a593Smuzhiyun 			optee->scan_bus_done = true;
253*4882a593Smuzhiyun 		}
254*4882a593Smuzhiyun 	}
255*4882a593Smuzhiyun 	mutex_init(&ctxdata->mutex);
256*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ctxdata->sess_list);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
259*4882a593Smuzhiyun 		ctx->cap_memref_null  = true;
260*4882a593Smuzhiyun 	else
261*4882a593Smuzhiyun 		ctx->cap_memref_null = false;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	ctx->data = ctxdata;
264*4882a593Smuzhiyun 	return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
optee_release(struct tee_context * ctx)267*4882a593Smuzhiyun static void optee_release(struct tee_context *ctx)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	struct optee_context_data *ctxdata = ctx->data;
270*4882a593Smuzhiyun 	struct tee_device *teedev = ctx->teedev;
271*4882a593Smuzhiyun 	struct optee *optee = tee_get_drvdata(teedev);
272*4882a593Smuzhiyun 	struct tee_shm *shm;
273*4882a593Smuzhiyun 	struct optee_msg_arg *arg = NULL;
274*4882a593Smuzhiyun 	phys_addr_t parg;
275*4882a593Smuzhiyun 	struct optee_session *sess;
276*4882a593Smuzhiyun 	struct optee_session *sess_tmp;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	if (!ctxdata)
279*4882a593Smuzhiyun 		return;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	shm = tee_shm_alloc(ctx, sizeof(struct optee_msg_arg),
282*4882a593Smuzhiyun 			    TEE_SHM_MAPPED | TEE_SHM_PRIV);
283*4882a593Smuzhiyun 	if (!IS_ERR(shm)) {
284*4882a593Smuzhiyun 		arg = tee_shm_get_va(shm, 0);
285*4882a593Smuzhiyun 		/*
286*4882a593Smuzhiyun 		 * If va2pa fails for some reason, we can't call into
287*4882a593Smuzhiyun 		 * secure world, only free the memory. Secure OS will leak
288*4882a593Smuzhiyun 		 * sessions and finally refuse more sessions, but we will
289*4882a593Smuzhiyun 		 * at least let normal world reclaim its memory.
290*4882a593Smuzhiyun 		 */
291*4882a593Smuzhiyun 		if (!IS_ERR(arg))
292*4882a593Smuzhiyun 			if (tee_shm_va2pa(shm, arg, &parg))
293*4882a593Smuzhiyun 				arg = NULL; /* prevent usage of parg below */
294*4882a593Smuzhiyun 	}
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	list_for_each_entry_safe(sess, sess_tmp, &ctxdata->sess_list,
297*4882a593Smuzhiyun 				 list_node) {
298*4882a593Smuzhiyun 		list_del(&sess->list_node);
299*4882a593Smuzhiyun 		if (!IS_ERR_OR_NULL(arg)) {
300*4882a593Smuzhiyun 			memset(arg, 0, sizeof(*arg));
301*4882a593Smuzhiyun 			arg->cmd = OPTEE_MSG_CMD_CLOSE_SESSION;
302*4882a593Smuzhiyun 			arg->session = sess->session_id;
303*4882a593Smuzhiyun 			optee_do_call_with_arg(ctx, parg);
304*4882a593Smuzhiyun 		}
305*4882a593Smuzhiyun 		kfree(sess);
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 	kfree(ctxdata);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	if (!IS_ERR(shm))
310*4882a593Smuzhiyun 		tee_shm_free(shm);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	ctx->data = NULL;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	if (teedev == optee->supp_teedev) {
315*4882a593Smuzhiyun 		if (optee->scan_bus_wq) {
316*4882a593Smuzhiyun 			destroy_workqueue(optee->scan_bus_wq);
317*4882a593Smuzhiyun 			optee->scan_bus_wq = NULL;
318*4882a593Smuzhiyun 		}
319*4882a593Smuzhiyun 		optee_supp_release(&optee->supp);
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun static const struct tee_driver_ops optee_ops = {
324*4882a593Smuzhiyun 	.get_version = optee_get_version,
325*4882a593Smuzhiyun 	.open = optee_open,
326*4882a593Smuzhiyun 	.release = optee_release,
327*4882a593Smuzhiyun 	.open_session = optee_open_session,
328*4882a593Smuzhiyun 	.close_session = optee_close_session,
329*4882a593Smuzhiyun 	.invoke_func = optee_invoke_func,
330*4882a593Smuzhiyun 	.cancel_req = optee_cancel_req,
331*4882a593Smuzhiyun 	.shm_register = optee_shm_register,
332*4882a593Smuzhiyun 	.shm_unregister = optee_shm_unregister,
333*4882a593Smuzhiyun };
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun static const struct tee_desc optee_desc = {
336*4882a593Smuzhiyun 	.name = DRIVER_NAME "-clnt",
337*4882a593Smuzhiyun 	.ops = &optee_ops,
338*4882a593Smuzhiyun 	.owner = THIS_MODULE,
339*4882a593Smuzhiyun };
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun static const struct tee_driver_ops optee_supp_ops = {
342*4882a593Smuzhiyun 	.get_version = optee_get_version,
343*4882a593Smuzhiyun 	.open = optee_open,
344*4882a593Smuzhiyun 	.release = optee_release,
345*4882a593Smuzhiyun 	.supp_recv = optee_supp_recv,
346*4882a593Smuzhiyun 	.supp_send = optee_supp_send,
347*4882a593Smuzhiyun 	.shm_register = optee_shm_register_supp,
348*4882a593Smuzhiyun 	.shm_unregister = optee_shm_unregister_supp,
349*4882a593Smuzhiyun };
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun static const struct tee_desc optee_supp_desc = {
352*4882a593Smuzhiyun 	.name = DRIVER_NAME "-supp",
353*4882a593Smuzhiyun 	.ops = &optee_supp_ops,
354*4882a593Smuzhiyun 	.owner = THIS_MODULE,
355*4882a593Smuzhiyun 	.flags = TEE_DESC_PRIVILEGED,
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun 
optee_msg_api_uid_is_optee_api(optee_invoke_fn * invoke_fn)358*4882a593Smuzhiyun static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun 	struct arm_smccc_res res;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 	if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
365*4882a593Smuzhiyun 	    res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3)
366*4882a593Smuzhiyun 		return true;
367*4882a593Smuzhiyun 	return false;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
optee_msg_get_os_revision(optee_invoke_fn * invoke_fn)370*4882a593Smuzhiyun static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	union {
373*4882a593Smuzhiyun 		struct arm_smccc_res smccc;
374*4882a593Smuzhiyun 		struct optee_smc_call_get_os_revision_result result;
375*4882a593Smuzhiyun 	} res = {
376*4882a593Smuzhiyun 		.result = {
377*4882a593Smuzhiyun 			.build_id = 0
378*4882a593Smuzhiyun 		}
379*4882a593Smuzhiyun 	};
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
382*4882a593Smuzhiyun 		  &res.smccc);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	if (res.result.build_id)
385*4882a593Smuzhiyun 		pr_info("revision %lu.%lu (%08lx)", res.result.major,
386*4882a593Smuzhiyun 			res.result.minor, res.result.build_id);
387*4882a593Smuzhiyun 	else
388*4882a593Smuzhiyun 		pr_info("revision %lu.%lu", res.result.major, res.result.minor);
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun 
optee_msg_api_revision_is_compatible(optee_invoke_fn * invoke_fn)391*4882a593Smuzhiyun static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn)
392*4882a593Smuzhiyun {
393*4882a593Smuzhiyun 	union {
394*4882a593Smuzhiyun 		struct arm_smccc_res smccc;
395*4882a593Smuzhiyun 		struct optee_smc_calls_revision_result result;
396*4882a593Smuzhiyun 	} res;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	if (res.result.major == OPTEE_MSG_REVISION_MAJOR &&
401*4882a593Smuzhiyun 	    (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR)
402*4882a593Smuzhiyun 		return true;
403*4882a593Smuzhiyun 	return false;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
optee_msg_exchange_capabilities(optee_invoke_fn * invoke_fn,u32 * sec_caps)406*4882a593Smuzhiyun static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
407*4882a593Smuzhiyun 					    u32 *sec_caps)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	union {
410*4882a593Smuzhiyun 		struct arm_smccc_res smccc;
411*4882a593Smuzhiyun 		struct optee_smc_exchange_capabilities_result result;
412*4882a593Smuzhiyun 	} res;
413*4882a593Smuzhiyun 	u32 a1 = 0;
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	/*
416*4882a593Smuzhiyun 	 * TODO This isn't enough to tell if it's UP system (from kernel
417*4882a593Smuzhiyun 	 * point of view) or not, is_smp() returns the the information
418*4882a593Smuzhiyun 	 * needed, but can't be called directly from here.
419*4882a593Smuzhiyun 	 */
420*4882a593Smuzhiyun 	if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1)
421*4882a593Smuzhiyun 		a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0,
424*4882a593Smuzhiyun 		  &res.smccc);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	if (res.result.status != OPTEE_SMC_RETURN_OK)
427*4882a593Smuzhiyun 		return false;
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	*sec_caps = res.result.capabilities;
430*4882a593Smuzhiyun 	return true;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
optee_config_dyn_shm(void)433*4882a593Smuzhiyun static struct tee_shm_pool *optee_config_dyn_shm(void)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	struct tee_shm_pool_mgr *priv_mgr;
436*4882a593Smuzhiyun 	struct tee_shm_pool_mgr *dmabuf_mgr;
437*4882a593Smuzhiyun 	void *rc;
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 	rc = optee_shm_pool_alloc_pages();
440*4882a593Smuzhiyun 	if (IS_ERR(rc))
441*4882a593Smuzhiyun 		return rc;
442*4882a593Smuzhiyun 	priv_mgr = rc;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	rc = optee_shm_pool_alloc_pages();
445*4882a593Smuzhiyun 	if (IS_ERR(rc)) {
446*4882a593Smuzhiyun 		tee_shm_pool_mgr_destroy(priv_mgr);
447*4882a593Smuzhiyun 		return rc;
448*4882a593Smuzhiyun 	}
449*4882a593Smuzhiyun 	dmabuf_mgr = rc;
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
452*4882a593Smuzhiyun 	if (IS_ERR(rc)) {
453*4882a593Smuzhiyun 		tee_shm_pool_mgr_destroy(priv_mgr);
454*4882a593Smuzhiyun 		tee_shm_pool_mgr_destroy(dmabuf_mgr);
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	return rc;
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn * invoke_fn,void ** memremaped_shm)461*4882a593Smuzhiyun optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
462*4882a593Smuzhiyun {
463*4882a593Smuzhiyun 	union {
464*4882a593Smuzhiyun 		struct arm_smccc_res smccc;
465*4882a593Smuzhiyun 		struct optee_smc_get_shm_config_result result;
466*4882a593Smuzhiyun 	} res;
467*4882a593Smuzhiyun 	unsigned long vaddr;
468*4882a593Smuzhiyun 	phys_addr_t paddr;
469*4882a593Smuzhiyun 	size_t size;
470*4882a593Smuzhiyun 	phys_addr_t begin;
471*4882a593Smuzhiyun 	phys_addr_t end;
472*4882a593Smuzhiyun 	void *va;
473*4882a593Smuzhiyun 	struct tee_shm_pool_mgr *priv_mgr;
474*4882a593Smuzhiyun 	struct tee_shm_pool_mgr *dmabuf_mgr;
475*4882a593Smuzhiyun 	void *rc;
476*4882a593Smuzhiyun 	const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
479*4882a593Smuzhiyun 	if (res.result.status != OPTEE_SMC_RETURN_OK) {
480*4882a593Smuzhiyun 		pr_err("static shm service not available\n");
481*4882a593Smuzhiyun 		return ERR_PTR(-ENOENT);
482*4882a593Smuzhiyun 	}
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
485*4882a593Smuzhiyun 		pr_err("only normal cached shared memory supported\n");
486*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	begin = roundup(res.result.start, PAGE_SIZE);
490*4882a593Smuzhiyun 	end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
491*4882a593Smuzhiyun 	paddr = begin;
492*4882a593Smuzhiyun 	size = end - begin;
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun 	if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) {
495*4882a593Smuzhiyun 		pr_err("too small shared memory area\n");
496*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
497*4882a593Smuzhiyun 	}
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	va = memremap(paddr, size, MEMREMAP_WB);
500*4882a593Smuzhiyun 	if (!va) {
501*4882a593Smuzhiyun 		pr_err("shared memory ioremap failed\n");
502*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
503*4882a593Smuzhiyun 	}
504*4882a593Smuzhiyun 	vaddr = (unsigned long)va;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 	rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
507*4882a593Smuzhiyun 					    3 /* 8 bytes aligned */);
508*4882a593Smuzhiyun 	if (IS_ERR(rc))
509*4882a593Smuzhiyun 		goto err_memunmap;
510*4882a593Smuzhiyun 	priv_mgr = rc;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	vaddr += sz;
513*4882a593Smuzhiyun 	paddr += sz;
514*4882a593Smuzhiyun 	size -= sz;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
517*4882a593Smuzhiyun 	if (IS_ERR(rc))
518*4882a593Smuzhiyun 		goto err_free_priv_mgr;
519*4882a593Smuzhiyun 	dmabuf_mgr = rc;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
522*4882a593Smuzhiyun 	if (IS_ERR(rc))
523*4882a593Smuzhiyun 		goto err_free_dmabuf_mgr;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	*memremaped_shm = va;
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	return rc;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun err_free_dmabuf_mgr:
530*4882a593Smuzhiyun 	tee_shm_pool_mgr_destroy(dmabuf_mgr);
531*4882a593Smuzhiyun err_free_priv_mgr:
532*4882a593Smuzhiyun 	tee_shm_pool_mgr_destroy(priv_mgr);
533*4882a593Smuzhiyun err_memunmap:
534*4882a593Smuzhiyun 	memunmap(va);
535*4882a593Smuzhiyun 	return rc;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun /* Simple wrapper functions to be able to use a function pointer */
optee_smccc_smc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)539*4882a593Smuzhiyun static void optee_smccc_smc(unsigned long a0, unsigned long a1,
540*4882a593Smuzhiyun 			    unsigned long a2, unsigned long a3,
541*4882a593Smuzhiyun 			    unsigned long a4, unsigned long a5,
542*4882a593Smuzhiyun 			    unsigned long a6, unsigned long a7,
543*4882a593Smuzhiyun 			    struct arm_smccc_res *res)
544*4882a593Smuzhiyun {
545*4882a593Smuzhiyun 	arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun 
optee_smccc_hvc(unsigned long a0,unsigned long a1,unsigned long a2,unsigned long a3,unsigned long a4,unsigned long a5,unsigned long a6,unsigned long a7,struct arm_smccc_res * res)548*4882a593Smuzhiyun static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
549*4882a593Smuzhiyun 			    unsigned long a2, unsigned long a3,
550*4882a593Smuzhiyun 			    unsigned long a4, unsigned long a5,
551*4882a593Smuzhiyun 			    unsigned long a6, unsigned long a7,
552*4882a593Smuzhiyun 			    struct arm_smccc_res *res)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
get_invoke_func(struct device * dev)557*4882a593Smuzhiyun static optee_invoke_fn *get_invoke_func(struct device *dev)
558*4882a593Smuzhiyun {
559*4882a593Smuzhiyun 	const char *method;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 	pr_info("probing for conduit method.\n");
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	if (device_property_read_string(dev, "method", &method)) {
564*4882a593Smuzhiyun 		pr_warn("missing \"method\" property\n");
565*4882a593Smuzhiyun 		return ERR_PTR(-ENXIO);
566*4882a593Smuzhiyun 	}
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	if (!strcmp("hvc", method))
569*4882a593Smuzhiyun 		return optee_smccc_hvc;
570*4882a593Smuzhiyun 	else if (!strcmp("smc", method))
571*4882a593Smuzhiyun 		return optee_smccc_smc;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	pr_warn("invalid \"method\" property: %s\n", method);
574*4882a593Smuzhiyun 	return ERR_PTR(-EINVAL);
575*4882a593Smuzhiyun }
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun /* optee_remove - Device Removal Routine
578*4882a593Smuzhiyun  * @pdev: platform device information struct
579*4882a593Smuzhiyun  *
580*4882a593Smuzhiyun  * optee_remove is called by platform subsystem to alert the driver
581*4882a593Smuzhiyun  * that it should release the device
582*4882a593Smuzhiyun  */
583*4882a593Smuzhiyun 
optee_remove(struct platform_device * pdev)584*4882a593Smuzhiyun static int optee_remove(struct platform_device *pdev)
585*4882a593Smuzhiyun {
586*4882a593Smuzhiyun 	struct optee *optee = platform_get_drvdata(pdev);
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	/* Unregister OP-TEE specific client devices on TEE bus */
589*4882a593Smuzhiyun 	optee_unregister_devices();
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	teedev_close_context(optee->ctx);
592*4882a593Smuzhiyun 	/*
593*4882a593Smuzhiyun 	 * Ask OP-TEE to free all cached shared memory objects to decrease
594*4882a593Smuzhiyun 	 * reference counters and also avoid wild pointers in secure world
595*4882a593Smuzhiyun 	 * into the old shared memory range.
596*4882a593Smuzhiyun 	 */
597*4882a593Smuzhiyun 	optee_disable_shm_cache(optee);
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	/*
600*4882a593Smuzhiyun 	 * The two devices have to be unregistered before we can free the
601*4882a593Smuzhiyun 	 * other resources.
602*4882a593Smuzhiyun 	 */
603*4882a593Smuzhiyun 	tee_device_unregister(optee->supp_teedev);
604*4882a593Smuzhiyun 	tee_device_unregister(optee->teedev);
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun 	tee_shm_pool_free(optee->pool);
607*4882a593Smuzhiyun 	if (optee->memremaped_shm)
608*4882a593Smuzhiyun 		memunmap(optee->memremaped_shm);
609*4882a593Smuzhiyun 	optee_wait_queue_exit(&optee->wait_queue);
610*4882a593Smuzhiyun 	optee_supp_uninit(&optee->supp);
611*4882a593Smuzhiyun 	mutex_destroy(&optee->call_queue.mutex);
612*4882a593Smuzhiyun 
613*4882a593Smuzhiyun 	kfree(optee);
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	return 0;
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun /* optee_shutdown - Device Removal Routine
619*4882a593Smuzhiyun  * @pdev: platform device information struct
620*4882a593Smuzhiyun  *
621*4882a593Smuzhiyun  * platform_shutdown is called by the platform subsystem to alert
622*4882a593Smuzhiyun  * the driver that a shutdown, reboot, or kexec is happening and
623*4882a593Smuzhiyun  * device must be disabled.
624*4882a593Smuzhiyun  */
optee_shutdown(struct platform_device * pdev)625*4882a593Smuzhiyun static void optee_shutdown(struct platform_device *pdev)
626*4882a593Smuzhiyun {
627*4882a593Smuzhiyun 	optee_disable_shm_cache(platform_get_drvdata(pdev));
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun 
optee_probe(struct platform_device * pdev)630*4882a593Smuzhiyun static int optee_probe(struct platform_device *pdev)
631*4882a593Smuzhiyun {
632*4882a593Smuzhiyun 	optee_invoke_fn *invoke_fn;
633*4882a593Smuzhiyun 	struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
634*4882a593Smuzhiyun 	struct optee *optee = NULL;
635*4882a593Smuzhiyun 	void *memremaped_shm = NULL;
636*4882a593Smuzhiyun 	struct tee_device *teedev;
637*4882a593Smuzhiyun 	struct tee_context *ctx;
638*4882a593Smuzhiyun 	u32 sec_caps;
639*4882a593Smuzhiyun 	int rc;
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	/*
642*4882a593Smuzhiyun 	 * The kernel may have crashed at the same time that all available
643*4882a593Smuzhiyun 	 * secure world threads were suspended and we cannot reschedule the
644*4882a593Smuzhiyun 	 * suspended threads without access to the crashed kernel's wait_queue.
645*4882a593Smuzhiyun 	 * Therefore, we cannot reliably initialize the OP-TEE driver in the
646*4882a593Smuzhiyun 	 * kdump kernel.
647*4882a593Smuzhiyun 	 */
648*4882a593Smuzhiyun 	if (is_kdump_kernel())
649*4882a593Smuzhiyun 		return -ENODEV;
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	invoke_fn = get_invoke_func(&pdev->dev);
652*4882a593Smuzhiyun 	if (IS_ERR(invoke_fn))
653*4882a593Smuzhiyun 		return PTR_ERR(invoke_fn);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
656*4882a593Smuzhiyun 		pr_warn("api uid mismatch\n");
657*4882a593Smuzhiyun 		return -EINVAL;
658*4882a593Smuzhiyun 	}
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	optee_msg_get_os_revision(invoke_fn);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
663*4882a593Smuzhiyun 		pr_warn("api revision mismatch\n");
664*4882a593Smuzhiyun 		return -EINVAL;
665*4882a593Smuzhiyun 	}
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps)) {
668*4882a593Smuzhiyun 		pr_warn("capabilities mismatch\n");
669*4882a593Smuzhiyun 		return -EINVAL;
670*4882a593Smuzhiyun 	}
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	/*
673*4882a593Smuzhiyun 	 * Try to use dynamic shared memory if possible
674*4882a593Smuzhiyun 	 */
675*4882a593Smuzhiyun 	if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
676*4882a593Smuzhiyun 		pool = optee_config_dyn_shm();
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	/*
679*4882a593Smuzhiyun 	 * If dynamic shared memory is not available or failed - try static one
680*4882a593Smuzhiyun 	 */
681*4882a593Smuzhiyun 	if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
682*4882a593Smuzhiyun 		pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	if (IS_ERR(pool))
685*4882a593Smuzhiyun 		return PTR_ERR(pool);
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
688*4882a593Smuzhiyun 	if (!optee) {
689*4882a593Smuzhiyun 		rc = -ENOMEM;
690*4882a593Smuzhiyun 		goto err;
691*4882a593Smuzhiyun 	}
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	optee->invoke_fn = invoke_fn;
694*4882a593Smuzhiyun 	optee->sec_caps = sec_caps;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun 	teedev = tee_device_alloc(&optee_desc, NULL, pool, optee);
697*4882a593Smuzhiyun 	if (IS_ERR(teedev)) {
698*4882a593Smuzhiyun 		rc = PTR_ERR(teedev);
699*4882a593Smuzhiyun 		goto err;
700*4882a593Smuzhiyun 	}
701*4882a593Smuzhiyun 	optee->teedev = teedev;
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
704*4882a593Smuzhiyun 	if (IS_ERR(teedev)) {
705*4882a593Smuzhiyun 		rc = PTR_ERR(teedev);
706*4882a593Smuzhiyun 		goto err;
707*4882a593Smuzhiyun 	}
708*4882a593Smuzhiyun 	optee->supp_teedev = teedev;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	rc = tee_device_register(optee->teedev);
711*4882a593Smuzhiyun 	if (rc)
712*4882a593Smuzhiyun 		goto err;
713*4882a593Smuzhiyun 
714*4882a593Smuzhiyun 	rc = tee_device_register(optee->supp_teedev);
715*4882a593Smuzhiyun 	if (rc)
716*4882a593Smuzhiyun 		goto err;
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	mutex_init(&optee->call_queue.mutex);
719*4882a593Smuzhiyun 	INIT_LIST_HEAD(&optee->call_queue.waiters);
720*4882a593Smuzhiyun 	optee_wait_queue_init(&optee->wait_queue);
721*4882a593Smuzhiyun 	optee_supp_init(&optee->supp);
722*4882a593Smuzhiyun 	optee->memremaped_shm = memremaped_shm;
723*4882a593Smuzhiyun 	optee->pool = pool;
724*4882a593Smuzhiyun 	ctx = teedev_open(optee->teedev);
725*4882a593Smuzhiyun 	if (IS_ERR(ctx)) {
726*4882a593Smuzhiyun 		rc = PTR_ERR(ctx);
727*4882a593Smuzhiyun 		goto err;
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 	optee->ctx = ctx;
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	/*
732*4882a593Smuzhiyun 	 * Ensure that there are no pre-existing shm objects before enabling
733*4882a593Smuzhiyun 	 * the shm cache so that there's no chance of receiving an invalid
734*4882a593Smuzhiyun 	 * address during shutdown. This could occur, for example, if we're
735*4882a593Smuzhiyun 	 * kexec booting from an older kernel that did not properly cleanup the
736*4882a593Smuzhiyun 	 * shm cache.
737*4882a593Smuzhiyun 	 */
738*4882a593Smuzhiyun 	optee_disable_unmapped_shm_cache(optee);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	optee_enable_shm_cache(optee);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
743*4882a593Smuzhiyun 		pr_info("dynamic shared memory is enabled\n");
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	platform_set_drvdata(pdev, optee);
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 	rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
748*4882a593Smuzhiyun 	if (rc) {
749*4882a593Smuzhiyun 		optee_remove(pdev);
750*4882a593Smuzhiyun 		return rc;
751*4882a593Smuzhiyun 	}
752*4882a593Smuzhiyun 
753*4882a593Smuzhiyun 	pr_info("initialized driver\n");
754*4882a593Smuzhiyun 	return 0;
755*4882a593Smuzhiyun err:
756*4882a593Smuzhiyun 	if (optee) {
757*4882a593Smuzhiyun 		/*
758*4882a593Smuzhiyun 		 * tee_device_unregister() is safe to call even if the
759*4882a593Smuzhiyun 		 * devices hasn't been registered with
760*4882a593Smuzhiyun 		 * tee_device_register() yet.
761*4882a593Smuzhiyun 		 */
762*4882a593Smuzhiyun 		tee_device_unregister(optee->supp_teedev);
763*4882a593Smuzhiyun 		tee_device_unregister(optee->teedev);
764*4882a593Smuzhiyun 		kfree(optee);
765*4882a593Smuzhiyun 	}
766*4882a593Smuzhiyun 	if (pool)
767*4882a593Smuzhiyun 		tee_shm_pool_free(pool);
768*4882a593Smuzhiyun 	if (memremaped_shm)
769*4882a593Smuzhiyun 		memunmap(memremaped_shm);
770*4882a593Smuzhiyun 	return rc;
771*4882a593Smuzhiyun }
772*4882a593Smuzhiyun 
773*4882a593Smuzhiyun static const struct of_device_id optee_dt_match[] = {
774*4882a593Smuzhiyun 	{ .compatible = "linaro,optee-tz" },
775*4882a593Smuzhiyun 	{},
776*4882a593Smuzhiyun };
777*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, optee_dt_match);
778*4882a593Smuzhiyun 
779*4882a593Smuzhiyun static struct platform_driver optee_driver = {
780*4882a593Smuzhiyun 	.probe  = optee_probe,
781*4882a593Smuzhiyun 	.remove = optee_remove,
782*4882a593Smuzhiyun 	.shutdown = optee_shutdown,
783*4882a593Smuzhiyun 	.driver = {
784*4882a593Smuzhiyun 		.name = "optee",
785*4882a593Smuzhiyun 		.of_match_table = optee_dt_match,
786*4882a593Smuzhiyun 	},
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun module_platform_driver(optee_driver);
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun MODULE_AUTHOR("Linaro");
791*4882a593Smuzhiyun MODULE_DESCRIPTION("OP-TEE driver");
792*4882a593Smuzhiyun MODULE_SUPPORTED_DEVICE("");
793*4882a593Smuzhiyun MODULE_VERSION("1.0");
794*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
795*4882a593Smuzhiyun MODULE_ALIAS("platform:optee");
796