xref: /openbmc/linux/drivers/tee/optee/smc_abi.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1c51a564aSJens Wiklander // SPDX-License-Identifier: GPL-2.0-only
2c51a564aSJens Wiklander /*
3c51a564aSJens Wiklander  * Copyright (c) 2015-2021, Linaro Limited
4c51a564aSJens Wiklander  * Copyright (c) 2016, EPAM Systems
5c51a564aSJens Wiklander  */
6c51a564aSJens Wiklander 
7c51a564aSJens Wiklander #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8c51a564aSJens Wiklander 
9c51a564aSJens Wiklander #include <linux/arm-smccc.h>
10f3040daaSJeffrey Kardatzke #include <linux/cpuhotplug.h>
11c51a564aSJens Wiklander #include <linux/errno.h>
12f3040daaSJeffrey Kardatzke #include <linux/firmware.h>
136749e69cSJens Wiklander #include <linux/interrupt.h>
14c51a564aSJens Wiklander #include <linux/io.h>
156749e69cSJens Wiklander #include <linux/irqdomain.h>
16f3040daaSJeffrey Kardatzke #include <linux/kernel.h>
1734f3c67bSJens Wiklander #include <linux/mm.h>
18c51a564aSJens Wiklander #include <linux/module.h>
19c51a564aSJens Wiklander #include <linux/of.h>
206749e69cSJens Wiklander #include <linux/of_irq.h>
21c51a564aSJens Wiklander #include <linux/of_platform.h>
22c51a564aSJens Wiklander #include <linux/platform_device.h>
236749e69cSJens Wiklander #include <linux/sched.h>
24c51a564aSJens Wiklander #include <linux/slab.h>
25c51a564aSJens Wiklander #include <linux/string.h>
26c51a564aSJens Wiklander #include <linux/tee_drv.h>
27c51a564aSJens Wiklander #include <linux/types.h>
28c51a564aSJens Wiklander #include <linux/workqueue.h>
29c51a564aSJens Wiklander #include "optee_private.h"
30c51a564aSJens Wiklander #include "optee_smc.h"
31c51a564aSJens Wiklander #include "optee_rpc_cmd.h"
326add87fdSXiaolei Wang #include <linux/kmemleak.h>
33c51a564aSJens Wiklander #define CREATE_TRACE_POINTS
34c51a564aSJens Wiklander #include "optee_trace.h"
35c51a564aSJens Wiklander 
36c51a564aSJens Wiklander /*
37c51a564aSJens Wiklander  * This file implement the SMC ABI used when communicating with secure world
38c51a564aSJens Wiklander  * OP-TEE OS via raw SMCs.
39c51a564aSJens Wiklander  * This file is divided into the following sections:
40c51a564aSJens Wiklander  * 1. Convert between struct tee_param and struct optee_msg_param
41c51a564aSJens Wiklander  * 2. Low level support functions to register shared memory in secure world
42c51a564aSJens Wiklander  * 3. Dynamic shared memory pool based on alloc_pages()
43c51a564aSJens Wiklander  * 4. Do a normal scheduled call into secure world
446749e69cSJens Wiklander  * 5. Asynchronous notification
456749e69cSJens Wiklander  * 6. Driver initialization.
46c51a564aSJens Wiklander  */
47c51a564aSJens Wiklander 
48d88e0493SJens Wiklander /*
49d88e0493SJens Wiklander  * A typical OP-TEE private shm allocation is 224 bytes (argument struct
50d88e0493SJens Wiklander  * with 6 parameters, needed for open session). So with an alignment of 512
51d88e0493SJens Wiklander  * we'll waste a bit more than 50%. However, it's only expected that we'll
52d88e0493SJens Wiklander  * have a handful of these structs allocated at a time. Most memory will
53d88e0493SJens Wiklander  * be allocated aligned to the page size, So all in all this should scale
54d88e0493SJens Wiklander  * up and down quite well.
55d88e0493SJens Wiklander  */
56d88e0493SJens Wiklander #define OPTEE_MIN_STATIC_POOL_ALIGN    9 /* 512 bytes aligned */
57c51a564aSJens Wiklander 
58b3b4ced1SEtienne Carriere /* SMC ABI considers at most a single TEE firmware */
59b3b4ced1SEtienne Carriere static unsigned int pcpu_irq_num;
60b3b4ced1SEtienne Carriere 
optee_cpuhp_enable_pcpu_irq(unsigned int cpu)61b3b4ced1SEtienne Carriere static int optee_cpuhp_enable_pcpu_irq(unsigned int cpu)
62b3b4ced1SEtienne Carriere {
63b3b4ced1SEtienne Carriere 	enable_percpu_irq(pcpu_irq_num, IRQ_TYPE_NONE);
64b3b4ced1SEtienne Carriere 
65b3b4ced1SEtienne Carriere 	return 0;
66b3b4ced1SEtienne Carriere }
67b3b4ced1SEtienne Carriere 
optee_cpuhp_disable_pcpu_irq(unsigned int cpu)68b3b4ced1SEtienne Carriere static int optee_cpuhp_disable_pcpu_irq(unsigned int cpu)
69b3b4ced1SEtienne Carriere {
70b3b4ced1SEtienne Carriere 	disable_percpu_irq(pcpu_irq_num);
71b3b4ced1SEtienne Carriere 
72b3b4ced1SEtienne Carriere 	return 0;
73b3b4ced1SEtienne Carriere }
74b3b4ced1SEtienne Carriere 
75c51a564aSJens Wiklander /*
76c51a564aSJens Wiklander  * 1. Convert between struct tee_param and struct optee_msg_param
77c51a564aSJens Wiklander  *
78c51a564aSJens Wiklander  * optee_from_msg_param() and optee_to_msg_param() are the main
79c51a564aSJens Wiklander  * functions.
80c51a564aSJens Wiklander  */
81c51a564aSJens Wiklander 
from_msg_param_tmp_mem(struct tee_param * p,u32 attr,const struct optee_msg_param * mp)82c51a564aSJens Wiklander static int from_msg_param_tmp_mem(struct tee_param *p, u32 attr,
83c51a564aSJens Wiklander 				  const struct optee_msg_param *mp)
84c51a564aSJens Wiklander {
85c51a564aSJens Wiklander 	struct tee_shm *shm;
86c51a564aSJens Wiklander 	phys_addr_t pa;
87c51a564aSJens Wiklander 	int rc;
88c51a564aSJens Wiklander 
89c51a564aSJens Wiklander 	p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
90c51a564aSJens Wiklander 		  attr - OPTEE_MSG_ATTR_TYPE_TMEM_INPUT;
91c51a564aSJens Wiklander 	p->u.memref.size = mp->u.tmem.size;
92c51a564aSJens Wiklander 	shm = (struct tee_shm *)(unsigned long)mp->u.tmem.shm_ref;
93c51a564aSJens Wiklander 	if (!shm) {
94c51a564aSJens Wiklander 		p->u.memref.shm_offs = 0;
95c51a564aSJens Wiklander 		p->u.memref.shm = NULL;
96c51a564aSJens Wiklander 		return 0;
97c51a564aSJens Wiklander 	}
98c51a564aSJens Wiklander 
99c51a564aSJens Wiklander 	rc = tee_shm_get_pa(shm, 0, &pa);
100c51a564aSJens Wiklander 	if (rc)
101c51a564aSJens Wiklander 		return rc;
102c51a564aSJens Wiklander 
103c51a564aSJens Wiklander 	p->u.memref.shm_offs = mp->u.tmem.buf_ptr - pa;
104c51a564aSJens Wiklander 	p->u.memref.shm = shm;
105c51a564aSJens Wiklander 
106c51a564aSJens Wiklander 	return 0;
107c51a564aSJens Wiklander }
108c51a564aSJens Wiklander 
from_msg_param_reg_mem(struct tee_param * p,u32 attr,const struct optee_msg_param * mp)109c51a564aSJens Wiklander static void from_msg_param_reg_mem(struct tee_param *p, u32 attr,
110c51a564aSJens Wiklander 				   const struct optee_msg_param *mp)
111c51a564aSJens Wiklander {
112c51a564aSJens Wiklander 	struct tee_shm *shm;
113c51a564aSJens Wiklander 
114c51a564aSJens Wiklander 	p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT +
115c51a564aSJens Wiklander 		  attr - OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
116c51a564aSJens Wiklander 	p->u.memref.size = mp->u.rmem.size;
117c51a564aSJens Wiklander 	shm = (struct tee_shm *)(unsigned long)mp->u.rmem.shm_ref;
118c51a564aSJens Wiklander 
119c51a564aSJens Wiklander 	if (shm) {
120c51a564aSJens Wiklander 		p->u.memref.shm_offs = mp->u.rmem.offs;
121c51a564aSJens Wiklander 		p->u.memref.shm = shm;
122c51a564aSJens Wiklander 	} else {
123c51a564aSJens Wiklander 		p->u.memref.shm_offs = 0;
124c51a564aSJens Wiklander 		p->u.memref.shm = NULL;
125c51a564aSJens Wiklander 	}
126c51a564aSJens Wiklander }
127c51a564aSJens Wiklander 
128c51a564aSJens Wiklander /**
129c51a564aSJens Wiklander  * optee_from_msg_param() - convert from OPTEE_MSG parameters to
130c51a564aSJens Wiklander  *			    struct tee_param
131c51a564aSJens Wiklander  * @optee:	main service struct
132c51a564aSJens Wiklander  * @params:	subsystem internal parameter representation
133c51a564aSJens Wiklander  * @num_params:	number of elements in the parameter arrays
134c51a564aSJens Wiklander  * @msg_params:	OPTEE_MSG parameters
135c51a564aSJens Wiklander  * Returns 0 on success or <0 on failure
136c51a564aSJens Wiklander  */
optee_from_msg_param(struct optee * optee,struct tee_param * params,size_t num_params,const struct optee_msg_param * msg_params)137c51a564aSJens Wiklander static int optee_from_msg_param(struct optee *optee, struct tee_param *params,
138c51a564aSJens Wiklander 				size_t num_params,
139c51a564aSJens Wiklander 				const struct optee_msg_param *msg_params)
140c51a564aSJens Wiklander {
141c51a564aSJens Wiklander 	int rc;
142c51a564aSJens Wiklander 	size_t n;
143c51a564aSJens Wiklander 
144c51a564aSJens Wiklander 	for (n = 0; n < num_params; n++) {
145c51a564aSJens Wiklander 		struct tee_param *p = params + n;
146c51a564aSJens Wiklander 		const struct optee_msg_param *mp = msg_params + n;
147c51a564aSJens Wiklander 		u32 attr = mp->attr & OPTEE_MSG_ATTR_TYPE_MASK;
148c51a564aSJens Wiklander 
149c51a564aSJens Wiklander 		switch (attr) {
150c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_NONE:
151c51a564aSJens Wiklander 			p->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
152c51a564aSJens Wiklander 			memset(&p->u, 0, sizeof(p->u));
153c51a564aSJens Wiklander 			break;
154c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_VALUE_INPUT:
155c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT:
156c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_VALUE_INOUT:
157c51a564aSJens Wiklander 			optee_from_msg_param_value(p, attr, mp);
158c51a564aSJens Wiklander 			break;
159c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_TMEM_INPUT:
160c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT:
161c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_TMEM_INOUT:
162c51a564aSJens Wiklander 			rc = from_msg_param_tmp_mem(p, attr, mp);
163c51a564aSJens Wiklander 			if (rc)
164c51a564aSJens Wiklander 				return rc;
165c51a564aSJens Wiklander 			break;
166c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_RMEM_INPUT:
167c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_RMEM_OUTPUT:
168c51a564aSJens Wiklander 		case OPTEE_MSG_ATTR_TYPE_RMEM_INOUT:
169c51a564aSJens Wiklander 			from_msg_param_reg_mem(p, attr, mp);
170c51a564aSJens Wiklander 			break;
171c51a564aSJens Wiklander 
172c51a564aSJens Wiklander 		default:
173c51a564aSJens Wiklander 			return -EINVAL;
174c51a564aSJens Wiklander 		}
175c51a564aSJens Wiklander 	}
176c51a564aSJens Wiklander 	return 0;
177c51a564aSJens Wiklander }
178c51a564aSJens Wiklander 
to_msg_param_tmp_mem(struct optee_msg_param * mp,const struct tee_param * p)179c51a564aSJens Wiklander static int to_msg_param_tmp_mem(struct optee_msg_param *mp,
180c51a564aSJens Wiklander 				const struct tee_param *p)
181c51a564aSJens Wiklander {
182c51a564aSJens Wiklander 	int rc;
183c51a564aSJens Wiklander 	phys_addr_t pa;
184c51a564aSJens Wiklander 
185c51a564aSJens Wiklander 	mp->attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT + p->attr -
186c51a564aSJens Wiklander 		   TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
187c51a564aSJens Wiklander 
188c51a564aSJens Wiklander 	mp->u.tmem.shm_ref = (unsigned long)p->u.memref.shm;
189c51a564aSJens Wiklander 	mp->u.tmem.size = p->u.memref.size;
190c51a564aSJens Wiklander 
191c51a564aSJens Wiklander 	if (!p->u.memref.shm) {
192c51a564aSJens Wiklander 		mp->u.tmem.buf_ptr = 0;
193c51a564aSJens Wiklander 		return 0;
194c51a564aSJens Wiklander 	}
195c51a564aSJens Wiklander 
196c51a564aSJens Wiklander 	rc = tee_shm_get_pa(p->u.memref.shm, p->u.memref.shm_offs, &pa);
197c51a564aSJens Wiklander 	if (rc)
198c51a564aSJens Wiklander 		return rc;
199c51a564aSJens Wiklander 
200c51a564aSJens Wiklander 	mp->u.tmem.buf_ptr = pa;
201c51a564aSJens Wiklander 	mp->attr |= OPTEE_MSG_ATTR_CACHE_PREDEFINED <<
202c51a564aSJens Wiklander 		    OPTEE_MSG_ATTR_CACHE_SHIFT;
203c51a564aSJens Wiklander 
204c51a564aSJens Wiklander 	return 0;
205c51a564aSJens Wiklander }
206c51a564aSJens Wiklander 
to_msg_param_reg_mem(struct optee_msg_param * mp,const struct tee_param * p)207c51a564aSJens Wiklander static int to_msg_param_reg_mem(struct optee_msg_param *mp,
208c51a564aSJens Wiklander 				const struct tee_param *p)
209c51a564aSJens Wiklander {
210c51a564aSJens Wiklander 	mp->attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT + p->attr -
211c51a564aSJens Wiklander 		   TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT;
212c51a564aSJens Wiklander 
213c51a564aSJens Wiklander 	mp->u.rmem.shm_ref = (unsigned long)p->u.memref.shm;
214c51a564aSJens Wiklander 	mp->u.rmem.size = p->u.memref.size;
215c51a564aSJens Wiklander 	mp->u.rmem.offs = p->u.memref.shm_offs;
216c51a564aSJens Wiklander 	return 0;
217c51a564aSJens Wiklander }
218c51a564aSJens Wiklander 
219c51a564aSJens Wiklander /**
220c51a564aSJens Wiklander  * optee_to_msg_param() - convert from struct tee_params to OPTEE_MSG parameters
221c51a564aSJens Wiklander  * @optee:	main service struct
222c51a564aSJens Wiklander  * @msg_params:	OPTEE_MSG parameters
223c51a564aSJens Wiklander  * @num_params:	number of elements in the parameter arrays
224c51a564aSJens Wiklander  * @params:	subsystem itnernal parameter representation
225c51a564aSJens Wiklander  * Returns 0 on success or <0 on failure
226c51a564aSJens Wiklander  */
optee_to_msg_param(struct optee * optee,struct optee_msg_param * msg_params,size_t num_params,const struct tee_param * params)227c51a564aSJens Wiklander static int optee_to_msg_param(struct optee *optee,
228c51a564aSJens Wiklander 			      struct optee_msg_param *msg_params,
229c51a564aSJens Wiklander 			      size_t num_params, const struct tee_param *params)
230c51a564aSJens Wiklander {
231c51a564aSJens Wiklander 	int rc;
232c51a564aSJens Wiklander 	size_t n;
233c51a564aSJens Wiklander 
234c51a564aSJens Wiklander 	for (n = 0; n < num_params; n++) {
235c51a564aSJens Wiklander 		const struct tee_param *p = params + n;
236c51a564aSJens Wiklander 		struct optee_msg_param *mp = msg_params + n;
237c51a564aSJens Wiklander 
238c51a564aSJens Wiklander 		switch (p->attr) {
239c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_NONE:
240c51a564aSJens Wiklander 			mp->attr = TEE_IOCTL_PARAM_ATTR_TYPE_NONE;
241c51a564aSJens Wiklander 			memset(&mp->u, 0, sizeof(mp->u));
242c51a564aSJens Wiklander 			break;
243c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT:
244c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT:
245c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT:
246c51a564aSJens Wiklander 			optee_to_msg_param_value(mp, p);
247c51a564aSJens Wiklander 			break;
248c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT:
249c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT:
250c51a564aSJens Wiklander 		case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT:
251a45ea4efSJens Wiklander 			if (tee_shm_is_dynamic(p->u.memref.shm))
252c51a564aSJens Wiklander 				rc = to_msg_param_reg_mem(mp, p);
253c51a564aSJens Wiklander 			else
254c51a564aSJens Wiklander 				rc = to_msg_param_tmp_mem(mp, p);
255c51a564aSJens Wiklander 			if (rc)
256c51a564aSJens Wiklander 				return rc;
257c51a564aSJens Wiklander 			break;
258c51a564aSJens Wiklander 		default:
259c51a564aSJens Wiklander 			return -EINVAL;
260c51a564aSJens Wiklander 		}
261c51a564aSJens Wiklander 	}
262c51a564aSJens Wiklander 	return 0;
263c51a564aSJens Wiklander }
264c51a564aSJens Wiklander 
265c51a564aSJens Wiklander /*
266c51a564aSJens Wiklander  * 2. Low level support functions to register shared memory in secure world
267c51a564aSJens Wiklander  *
268c51a564aSJens Wiklander  * Functions to enable/disable shared memory caching in secure world, that
269c51a564aSJens Wiklander  * is, lazy freeing of previously allocated shared memory. Freeing is
270c51a564aSJens Wiklander  * performed when a request has been compled.
271c51a564aSJens Wiklander  *
272c51a564aSJens Wiklander  * Functions to register and unregister shared memory both for normal
273c51a564aSJens Wiklander  * clients and for tee-supplicant.
274c51a564aSJens Wiklander  */
275c51a564aSJens Wiklander 
276c51a564aSJens Wiklander /**
277c51a564aSJens Wiklander  * optee_enable_shm_cache() - Enables caching of some shared memory allocation
278c51a564aSJens Wiklander  *			      in OP-TEE
279c51a564aSJens Wiklander  * @optee:	main service struct
280c51a564aSJens Wiklander  */
optee_enable_shm_cache(struct optee * optee)281c51a564aSJens Wiklander static void optee_enable_shm_cache(struct optee *optee)
282c51a564aSJens Wiklander {
283c51a564aSJens Wiklander 	struct optee_call_waiter w;
284c51a564aSJens Wiklander 
285c51a564aSJens Wiklander 	/* We need to retry until secure world isn't busy. */
286c51a564aSJens Wiklander 	optee_cq_wait_init(&optee->call_queue, &w);
287c51a564aSJens Wiklander 	while (true) {
288c51a564aSJens Wiklander 		struct arm_smccc_res res;
289c51a564aSJens Wiklander 
290c51a564aSJens Wiklander 		optee->smc.invoke_fn(OPTEE_SMC_ENABLE_SHM_CACHE,
291c51a564aSJens Wiklander 				     0, 0, 0, 0, 0, 0, 0, &res);
292c51a564aSJens Wiklander 		if (res.a0 == OPTEE_SMC_RETURN_OK)
293c51a564aSJens Wiklander 			break;
294c51a564aSJens Wiklander 		optee_cq_wait_for_completion(&optee->call_queue, &w);
295c51a564aSJens Wiklander 	}
296c51a564aSJens Wiklander 	optee_cq_wait_final(&optee->call_queue, &w);
297c51a564aSJens Wiklander }
298c51a564aSJens Wiklander 
299c51a564aSJens Wiklander /**
300c51a564aSJens Wiklander  * __optee_disable_shm_cache() - Disables caching of some shared memory
301c51a564aSJens Wiklander  *				 allocation in OP-TEE
302c51a564aSJens Wiklander  * @optee:	main service struct
303c51a564aSJens Wiklander  * @is_mapped:	true if the cached shared memory addresses were mapped by this
304c51a564aSJens Wiklander  *		kernel, are safe to dereference, and should be freed
305c51a564aSJens Wiklander  */
__optee_disable_shm_cache(struct optee * optee,bool is_mapped)306c51a564aSJens Wiklander static void __optee_disable_shm_cache(struct optee *optee, bool is_mapped)
307c51a564aSJens Wiklander {
308c51a564aSJens Wiklander 	struct optee_call_waiter w;
309c51a564aSJens Wiklander 
310c51a564aSJens Wiklander 	/* We need to retry until secure world isn't busy. */
311c51a564aSJens Wiklander 	optee_cq_wait_init(&optee->call_queue, &w);
312c51a564aSJens Wiklander 	while (true) {
313c51a564aSJens Wiklander 		union {
314c51a564aSJens Wiklander 			struct arm_smccc_res smccc;
315c51a564aSJens Wiklander 			struct optee_smc_disable_shm_cache_result result;
316c51a564aSJens Wiklander 		} res;
317c51a564aSJens Wiklander 
318c51a564aSJens Wiklander 		optee->smc.invoke_fn(OPTEE_SMC_DISABLE_SHM_CACHE,
319c51a564aSJens Wiklander 				     0, 0, 0, 0, 0, 0, 0, &res.smccc);
320c51a564aSJens Wiklander 		if (res.result.status == OPTEE_SMC_RETURN_ENOTAVAIL)
321c51a564aSJens Wiklander 			break; /* All shm's freed */
322c51a564aSJens Wiklander 		if (res.result.status == OPTEE_SMC_RETURN_OK) {
323c51a564aSJens Wiklander 			struct tee_shm *shm;
324c51a564aSJens Wiklander 
325c51a564aSJens Wiklander 			/*
326c51a564aSJens Wiklander 			 * Shared memory references that were not mapped by
327c51a564aSJens Wiklander 			 * this kernel must be ignored to prevent a crash.
328c51a564aSJens Wiklander 			 */
329c51a564aSJens Wiklander 			if (!is_mapped)
330c51a564aSJens Wiklander 				continue;
331c51a564aSJens Wiklander 
332c51a564aSJens Wiklander 			shm = reg_pair_to_ptr(res.result.shm_upper32,
333c51a564aSJens Wiklander 					      res.result.shm_lower32);
334c51a564aSJens Wiklander 			tee_shm_free(shm);
335c51a564aSJens Wiklander 		} else {
336c51a564aSJens Wiklander 			optee_cq_wait_for_completion(&optee->call_queue, &w);
337c51a564aSJens Wiklander 		}
338c51a564aSJens Wiklander 	}
339c51a564aSJens Wiklander 	optee_cq_wait_final(&optee->call_queue, &w);
340c51a564aSJens Wiklander }
341c51a564aSJens Wiklander 
342c51a564aSJens Wiklander /**
343c51a564aSJens Wiklander  * optee_disable_shm_cache() - Disables caching of mapped shared memory
344c51a564aSJens Wiklander  *			       allocations in OP-TEE
345c51a564aSJens Wiklander  * @optee:	main service struct
346c51a564aSJens Wiklander  */
optee_disable_shm_cache(struct optee * optee)347c51a564aSJens Wiklander static void optee_disable_shm_cache(struct optee *optee)
348c51a564aSJens Wiklander {
349c51a564aSJens Wiklander 	return __optee_disable_shm_cache(optee, true);
350c51a564aSJens Wiklander }
351c51a564aSJens Wiklander 
352c51a564aSJens Wiklander /**
353c51a564aSJens Wiklander  * optee_disable_unmapped_shm_cache() - Disables caching of shared memory
354c51a564aSJens Wiklander  *					allocations in OP-TEE which are not
355c51a564aSJens Wiklander  *					currently mapped
356c51a564aSJens Wiklander  * @optee:	main service struct
357c51a564aSJens Wiklander  */
optee_disable_unmapped_shm_cache(struct optee * optee)358c51a564aSJens Wiklander static void optee_disable_unmapped_shm_cache(struct optee *optee)
359c51a564aSJens Wiklander {
360c51a564aSJens Wiklander 	return __optee_disable_shm_cache(optee, false);
361c51a564aSJens Wiklander }
362c51a564aSJens Wiklander 
363c51a564aSJens Wiklander #define PAGELIST_ENTRIES_PER_PAGE				\
364c51a564aSJens Wiklander 	((OPTEE_MSG_NONCONTIG_PAGE_SIZE / sizeof(u64)) - 1)
365c51a564aSJens Wiklander 
366c51a564aSJens Wiklander /*
367c51a564aSJens Wiklander  * The final entry in each pagelist page is a pointer to the next
368c51a564aSJens Wiklander  * pagelist page.
369c51a564aSJens Wiklander  */
get_pages_list_size(size_t num_entries)370c51a564aSJens Wiklander static size_t get_pages_list_size(size_t num_entries)
371c51a564aSJens Wiklander {
372c51a564aSJens Wiklander 	int pages = DIV_ROUND_UP(num_entries, PAGELIST_ENTRIES_PER_PAGE);
373c51a564aSJens Wiklander 
374c51a564aSJens Wiklander 	return pages * OPTEE_MSG_NONCONTIG_PAGE_SIZE;
375c51a564aSJens Wiklander }
376c51a564aSJens Wiklander 
optee_allocate_pages_list(size_t num_entries)377c51a564aSJens Wiklander static u64 *optee_allocate_pages_list(size_t num_entries)
378c51a564aSJens Wiklander {
379c51a564aSJens Wiklander 	return alloc_pages_exact(get_pages_list_size(num_entries), GFP_KERNEL);
380c51a564aSJens Wiklander }
381c51a564aSJens Wiklander 
optee_free_pages_list(void * list,size_t num_entries)382c51a564aSJens Wiklander static void optee_free_pages_list(void *list, size_t num_entries)
383c51a564aSJens Wiklander {
384c51a564aSJens Wiklander 	free_pages_exact(list, get_pages_list_size(num_entries));
385c51a564aSJens Wiklander }
386c51a564aSJens Wiklander 
387c51a564aSJens Wiklander /**
388c51a564aSJens Wiklander  * optee_fill_pages_list() - write list of user pages to given shared
389c51a564aSJens Wiklander  * buffer.
390c51a564aSJens Wiklander  *
391c51a564aSJens Wiklander  * @dst: page-aligned buffer where list of pages will be stored
392c51a564aSJens Wiklander  * @pages: array of pages that represents shared buffer
393c51a564aSJens Wiklander  * @num_pages: number of entries in @pages
394c51a564aSJens Wiklander  * @page_offset: offset of user buffer from page start
395c51a564aSJens Wiklander  *
396c51a564aSJens Wiklander  * @dst should be big enough to hold list of user page addresses and
397c51a564aSJens Wiklander  *	links to the next pages of buffer
398c51a564aSJens Wiklander  */
optee_fill_pages_list(u64 * dst,struct page ** pages,int num_pages,size_t page_offset)399c51a564aSJens Wiklander static void optee_fill_pages_list(u64 *dst, struct page **pages, int num_pages,
400c51a564aSJens Wiklander 				  size_t page_offset)
401c51a564aSJens Wiklander {
402c51a564aSJens Wiklander 	int n = 0;
403c51a564aSJens Wiklander 	phys_addr_t optee_page;
404c51a564aSJens Wiklander 	/*
405c51a564aSJens Wiklander 	 * Refer to OPTEE_MSG_ATTR_NONCONTIG description in optee_msg.h
406c51a564aSJens Wiklander 	 * for details.
407c51a564aSJens Wiklander 	 */
408c51a564aSJens Wiklander 	struct {
409c51a564aSJens Wiklander 		u64 pages_list[PAGELIST_ENTRIES_PER_PAGE];
410c51a564aSJens Wiklander 		u64 next_page_data;
411c51a564aSJens Wiklander 	} *pages_data;
412c51a564aSJens Wiklander 
413c51a564aSJens Wiklander 	/*
414c51a564aSJens Wiklander 	 * Currently OP-TEE uses 4k page size and it does not looks
415c51a564aSJens Wiklander 	 * like this will change in the future.  On other hand, there are
416c51a564aSJens Wiklander 	 * no know ARM architectures with page size < 4k.
417c51a564aSJens Wiklander 	 * Thus the next built assert looks redundant. But the following
418c51a564aSJens Wiklander 	 * code heavily relies on this assumption, so it is better be
419c51a564aSJens Wiklander 	 * safe than sorry.
420c51a564aSJens Wiklander 	 */
421c51a564aSJens Wiklander 	BUILD_BUG_ON(PAGE_SIZE < OPTEE_MSG_NONCONTIG_PAGE_SIZE);
422c51a564aSJens Wiklander 
423c51a564aSJens Wiklander 	pages_data = (void *)dst;
424c51a564aSJens Wiklander 	/*
425c51a564aSJens Wiklander 	 * If linux page is bigger than 4k, and user buffer offset is
426c51a564aSJens Wiklander 	 * larger than 4k/8k/12k/etc this will skip first 4k pages,
427c51a564aSJens Wiklander 	 * because they bear no value data for OP-TEE.
428c51a564aSJens Wiklander 	 */
429c51a564aSJens Wiklander 	optee_page = page_to_phys(*pages) +
430c51a564aSJens Wiklander 		round_down(page_offset, OPTEE_MSG_NONCONTIG_PAGE_SIZE);
431c51a564aSJens Wiklander 
432c51a564aSJens Wiklander 	while (true) {
433c51a564aSJens Wiklander 		pages_data->pages_list[n++] = optee_page;
434c51a564aSJens Wiklander 
435c51a564aSJens Wiklander 		if (n == PAGELIST_ENTRIES_PER_PAGE) {
436c51a564aSJens Wiklander 			pages_data->next_page_data =
437c51a564aSJens Wiklander 				virt_to_phys(pages_data + 1);
438c51a564aSJens Wiklander 			pages_data++;
439c51a564aSJens Wiklander 			n = 0;
440c51a564aSJens Wiklander 		}
441c51a564aSJens Wiklander 
442c51a564aSJens Wiklander 		optee_page += OPTEE_MSG_NONCONTIG_PAGE_SIZE;
443c51a564aSJens Wiklander 		if (!(optee_page & ~PAGE_MASK)) {
444c51a564aSJens Wiklander 			if (!--num_pages)
445c51a564aSJens Wiklander 				break;
446c51a564aSJens Wiklander 			pages++;
447c51a564aSJens Wiklander 			optee_page = page_to_phys(*pages);
448c51a564aSJens Wiklander 		}
449c51a564aSJens Wiklander 	}
450c51a564aSJens Wiklander }
451c51a564aSJens Wiklander 
optee_shm_register(struct tee_context * ctx,struct tee_shm * shm,struct page ** pages,size_t num_pages,unsigned long start)452c51a564aSJens Wiklander static int optee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
453c51a564aSJens Wiklander 			      struct page **pages, size_t num_pages,
454c51a564aSJens Wiklander 			      unsigned long start)
455c51a564aSJens Wiklander {
456c51a564aSJens Wiklander 	struct optee *optee = tee_get_drvdata(ctx->teedev);
457c51a564aSJens Wiklander 	struct optee_msg_arg *msg_arg;
458c51a564aSJens Wiklander 	struct tee_shm *shm_arg;
459c51a564aSJens Wiklander 	u64 *pages_list;
4605b4018b9SJens Wiklander 	size_t sz;
461c51a564aSJens Wiklander 	int rc;
462c51a564aSJens Wiklander 
463c51a564aSJens Wiklander 	if (!num_pages)
464c51a564aSJens Wiklander 		return -EINVAL;
465c51a564aSJens Wiklander 
466c51a564aSJens Wiklander 	rc = optee_check_mem_type(start, num_pages);
467c51a564aSJens Wiklander 	if (rc)
468c51a564aSJens Wiklander 		return rc;
469c51a564aSJens Wiklander 
470c51a564aSJens Wiklander 	pages_list = optee_allocate_pages_list(num_pages);
471c51a564aSJens Wiklander 	if (!pages_list)
472c51a564aSJens Wiklander 		return -ENOMEM;
473c51a564aSJens Wiklander 
4745b4018b9SJens Wiklander 	/*
4755b4018b9SJens Wiklander 	 * We're about to register shared memory we can't register shared
4765b4018b9SJens Wiklander 	 * memory for this request or there's a catch-22.
4775b4018b9SJens Wiklander 	 *
4785b4018b9SJens Wiklander 	 * So in this we'll have to do the good old temporary private
4795b4018b9SJens Wiklander 	 * allocation instead of using optee_get_msg_arg().
4805b4018b9SJens Wiklander 	 */
4815b4018b9SJens Wiklander 	sz = optee_msg_arg_size(optee->rpc_param_count);
4825b4018b9SJens Wiklander 	shm_arg = tee_shm_alloc_priv_buf(ctx, sz);
483c51a564aSJens Wiklander 	if (IS_ERR(shm_arg)) {
484c51a564aSJens Wiklander 		rc = PTR_ERR(shm_arg);
485c51a564aSJens Wiklander 		goto out;
486c51a564aSJens Wiklander 	}
4875b4018b9SJens Wiklander 	msg_arg = tee_shm_get_va(shm_arg, 0);
4885b4018b9SJens Wiklander 	if (IS_ERR(msg_arg)) {
4895b4018b9SJens Wiklander 		rc = PTR_ERR(msg_arg);
4905b4018b9SJens Wiklander 		goto out;
4915b4018b9SJens Wiklander 	}
492c51a564aSJens Wiklander 
493c51a564aSJens Wiklander 	optee_fill_pages_list(pages_list, pages, num_pages,
494c51a564aSJens Wiklander 			      tee_shm_get_page_offset(shm));
495c51a564aSJens Wiklander 
4965b4018b9SJens Wiklander 	memset(msg_arg, 0, OPTEE_MSG_GET_ARG_SIZE(1));
4975b4018b9SJens Wiklander 	msg_arg->num_params = 1;
498c51a564aSJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_REGISTER_SHM;
499c51a564aSJens Wiklander 	msg_arg->params->attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
500c51a564aSJens Wiklander 				OPTEE_MSG_ATTR_NONCONTIG;
501c51a564aSJens Wiklander 	msg_arg->params->u.tmem.shm_ref = (unsigned long)shm;
502c51a564aSJens Wiklander 	msg_arg->params->u.tmem.size = tee_shm_get_size(shm);
503c51a564aSJens Wiklander 	/*
504c51a564aSJens Wiklander 	 * In the least bits of msg_arg->params->u.tmem.buf_ptr we
505c51a564aSJens Wiklander 	 * store buffer offset from 4k page, as described in OP-TEE ABI.
506c51a564aSJens Wiklander 	 */
507c51a564aSJens Wiklander 	msg_arg->params->u.tmem.buf_ptr = virt_to_phys(pages_list) |
508c51a564aSJens Wiklander 	  (tee_shm_get_page_offset(shm) & (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
509c51a564aSJens Wiklander 
5105b4018b9SJens Wiklander 	if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) ||
511c51a564aSJens Wiklander 	    msg_arg->ret != TEEC_SUCCESS)
512c51a564aSJens Wiklander 		rc = -EINVAL;
513c51a564aSJens Wiklander 
514c51a564aSJens Wiklander 	tee_shm_free(shm_arg);
515c51a564aSJens Wiklander out:
516c51a564aSJens Wiklander 	optee_free_pages_list(pages_list, num_pages);
517c51a564aSJens Wiklander 	return rc;
518c51a564aSJens Wiklander }
519c51a564aSJens Wiklander 
optee_shm_unregister(struct tee_context * ctx,struct tee_shm * shm)520c51a564aSJens Wiklander static int optee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
521c51a564aSJens Wiklander {
522c51a564aSJens Wiklander 	struct optee *optee = tee_get_drvdata(ctx->teedev);
523c51a564aSJens Wiklander 	struct optee_msg_arg *msg_arg;
524c51a564aSJens Wiklander 	struct tee_shm *shm_arg;
525c51a564aSJens Wiklander 	int rc = 0;
5265b4018b9SJens Wiklander 	size_t sz;
527c51a564aSJens Wiklander 
5285b4018b9SJens Wiklander 	/*
5295b4018b9SJens Wiklander 	 * We're about to unregister shared memory and we may not be able
5305b4018b9SJens Wiklander 	 * register shared memory for this request in case we're called
5315b4018b9SJens Wiklander 	 * from optee_shm_arg_cache_uninit().
5325b4018b9SJens Wiklander 	 *
5335b4018b9SJens Wiklander 	 * So in order to keep things simple in this function just as in
5345b4018b9SJens Wiklander 	 * optee_shm_register() we'll use temporary private allocation
5355b4018b9SJens Wiklander 	 * instead of using optee_get_msg_arg().
5365b4018b9SJens Wiklander 	 */
5375b4018b9SJens Wiklander 	sz = optee_msg_arg_size(optee->rpc_param_count);
5385b4018b9SJens Wiklander 	shm_arg = tee_shm_alloc_priv_buf(ctx, sz);
539c51a564aSJens Wiklander 	if (IS_ERR(shm_arg))
540c51a564aSJens Wiklander 		return PTR_ERR(shm_arg);
5415b4018b9SJens Wiklander 	msg_arg = tee_shm_get_va(shm_arg, 0);
5425b4018b9SJens Wiklander 	if (IS_ERR(msg_arg)) {
5435b4018b9SJens Wiklander 		rc = PTR_ERR(msg_arg);
5445b4018b9SJens Wiklander 		goto out;
5455b4018b9SJens Wiklander 	}
546c51a564aSJens Wiklander 
5475b4018b9SJens Wiklander 	memset(msg_arg, 0, sz);
5485b4018b9SJens Wiklander 	msg_arg->num_params = 1;
549c51a564aSJens Wiklander 	msg_arg->cmd = OPTEE_MSG_CMD_UNREGISTER_SHM;
550c51a564aSJens Wiklander 	msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT;
551c51a564aSJens Wiklander 	msg_arg->params[0].u.rmem.shm_ref = (unsigned long)shm;
552c51a564aSJens Wiklander 
5535b4018b9SJens Wiklander 	if (optee->ops->do_call_with_arg(ctx, shm_arg, 0) ||
554c51a564aSJens Wiklander 	    msg_arg->ret != TEEC_SUCCESS)
555c51a564aSJens Wiklander 		rc = -EINVAL;
5565b4018b9SJens Wiklander out:
557c51a564aSJens Wiklander 	tee_shm_free(shm_arg);
558c51a564aSJens Wiklander 	return rc;
559c51a564aSJens Wiklander }
560c51a564aSJens Wiklander 
optee_shm_register_supp(struct tee_context * ctx,struct tee_shm * shm,struct page ** pages,size_t num_pages,unsigned long start)561c51a564aSJens Wiklander static int optee_shm_register_supp(struct tee_context *ctx, struct tee_shm *shm,
562c51a564aSJens Wiklander 				   struct page **pages, size_t num_pages,
563c51a564aSJens Wiklander 				   unsigned long start)
564c51a564aSJens Wiklander {
565c51a564aSJens Wiklander 	/*
566c51a564aSJens Wiklander 	 * We don't want to register supplicant memory in OP-TEE.
567c51a564aSJens Wiklander 	 * Instead information about it will be passed in RPC code.
568c51a564aSJens Wiklander 	 */
569c51a564aSJens Wiklander 	return optee_check_mem_type(start, num_pages);
570c51a564aSJens Wiklander }
571c51a564aSJens Wiklander 
optee_shm_unregister_supp(struct tee_context * ctx,struct tee_shm * shm)572c51a564aSJens Wiklander static int optee_shm_unregister_supp(struct tee_context *ctx,
573c51a564aSJens Wiklander 				     struct tee_shm *shm)
574c51a564aSJens Wiklander {
575c51a564aSJens Wiklander 	return 0;
576c51a564aSJens Wiklander }
577c51a564aSJens Wiklander 
578c51a564aSJens Wiklander /*
579c51a564aSJens Wiklander  * 3. Dynamic shared memory pool based on alloc_pages()
580c51a564aSJens Wiklander  *
581c51a564aSJens Wiklander  * Implements an OP-TEE specific shared memory pool which is used
582c51a564aSJens Wiklander  * when dynamic shared memory is supported by secure world.
583c51a564aSJens Wiklander  *
584c51a564aSJens Wiklander  * The main function is optee_shm_pool_alloc_pages().
585c51a564aSJens Wiklander  */
586c51a564aSJens Wiklander 
pool_op_alloc(struct tee_shm_pool * pool,struct tee_shm * shm,size_t size,size_t align)587d88e0493SJens Wiklander static int pool_op_alloc(struct tee_shm_pool *pool,
588d88e0493SJens Wiklander 			 struct tee_shm *shm, size_t size, size_t align)
589c51a564aSJens Wiklander {
590c51a564aSJens Wiklander 	/*
591c51a564aSJens Wiklander 	 * Shared memory private to the OP-TEE driver doesn't need
592c51a564aSJens Wiklander 	 * to be registered with OP-TEE.
593c51a564aSJens Wiklander 	 */
594c51a564aSJens Wiklander 	if (shm->flags & TEE_SHM_PRIV)
595d88e0493SJens Wiklander 		return optee_pool_op_alloc_helper(pool, shm, size, align, NULL);
596c51a564aSJens Wiklander 
597d88e0493SJens Wiklander 	return optee_pool_op_alloc_helper(pool, shm, size, align,
598d88e0493SJens Wiklander 					  optee_shm_register);
599c51a564aSJens Wiklander }
600c51a564aSJens Wiklander 
pool_op_free(struct tee_shm_pool * pool,struct tee_shm * shm)601d88e0493SJens Wiklander static void pool_op_free(struct tee_shm_pool *pool,
602c51a564aSJens Wiklander 			 struct tee_shm *shm)
603c51a564aSJens Wiklander {
604c51a564aSJens Wiklander 	if (!(shm->flags & TEE_SHM_PRIV))
605924e3226SJens Wiklander 		optee_pool_op_free_helper(pool, shm, optee_shm_unregister);
606924e3226SJens Wiklander 	else
607924e3226SJens Wiklander 		optee_pool_op_free_helper(pool, shm, NULL);
608c51a564aSJens Wiklander }
609c51a564aSJens Wiklander 
pool_op_destroy_pool(struct tee_shm_pool * pool)610d88e0493SJens Wiklander static void pool_op_destroy_pool(struct tee_shm_pool *pool)
611c51a564aSJens Wiklander {
612d88e0493SJens Wiklander 	kfree(pool);
613c51a564aSJens Wiklander }
614c51a564aSJens Wiklander 
615d88e0493SJens Wiklander static const struct tee_shm_pool_ops pool_ops = {
616c51a564aSJens Wiklander 	.alloc = pool_op_alloc,
617c51a564aSJens Wiklander 	.free = pool_op_free,
618d88e0493SJens Wiklander 	.destroy_pool = pool_op_destroy_pool,
619c51a564aSJens Wiklander };
620c51a564aSJens Wiklander 
621c51a564aSJens Wiklander /**
622c51a564aSJens Wiklander  * optee_shm_pool_alloc_pages() - create page-based allocator pool
623c51a564aSJens Wiklander  *
624c51a564aSJens Wiklander  * This pool is used when OP-TEE supports dymanic SHM. In this case
625c51a564aSJens Wiklander  * command buffers and such are allocated from kernel's own memory.
626c51a564aSJens Wiklander  */
optee_shm_pool_alloc_pages(void)627d88e0493SJens Wiklander static struct tee_shm_pool *optee_shm_pool_alloc_pages(void)
628c51a564aSJens Wiklander {
629d88e0493SJens Wiklander 	struct tee_shm_pool *pool = kzalloc(sizeof(*pool), GFP_KERNEL);
630c51a564aSJens Wiklander 
631d88e0493SJens Wiklander 	if (!pool)
632c51a564aSJens Wiklander 		return ERR_PTR(-ENOMEM);
633c51a564aSJens Wiklander 
634d88e0493SJens Wiklander 	pool->ops = &pool_ops;
635c51a564aSJens Wiklander 
636d88e0493SJens Wiklander 	return pool;
637c51a564aSJens Wiklander }
638c51a564aSJens Wiklander 
639c51a564aSJens Wiklander /*
640c51a564aSJens Wiklander  * 4. Do a normal scheduled call into secure world
641c51a564aSJens Wiklander  *
642c51a564aSJens Wiklander  * The function optee_smc_do_call_with_arg() performs a normal scheduled
643c51a564aSJens Wiklander  * call into secure world. During this call may normal world request help
644c51a564aSJens Wiklander  * from normal world using RPCs, Remote Procedure Calls. This includes
645c51a564aSJens Wiklander  * delivery of non-secure interrupts to for instance allow rescheduling of
646c51a564aSJens Wiklander  * the current task.
647c51a564aSJens Wiklander  */
648c51a564aSJens Wiklander 
handle_rpc_func_cmd_shm_free(struct tee_context * ctx,struct optee_msg_arg * arg)649c51a564aSJens Wiklander static void handle_rpc_func_cmd_shm_free(struct tee_context *ctx,
650c51a564aSJens Wiklander 					 struct optee_msg_arg *arg)
651c51a564aSJens Wiklander {
652c51a564aSJens Wiklander 	struct tee_shm *shm;
653c51a564aSJens Wiklander 
654c51a564aSJens Wiklander 	arg->ret_origin = TEEC_ORIGIN_COMMS;
655c51a564aSJens Wiklander 
656c51a564aSJens Wiklander 	if (arg->num_params != 1 ||
657c51a564aSJens Wiklander 	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
658c51a564aSJens Wiklander 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
659c51a564aSJens Wiklander 		return;
660c51a564aSJens Wiklander 	}
661c51a564aSJens Wiklander 
662c51a564aSJens Wiklander 	shm = (struct tee_shm *)(unsigned long)arg->params[0].u.value.b;
663c51a564aSJens Wiklander 	switch (arg->params[0].u.value.a) {
664c51a564aSJens Wiklander 	case OPTEE_RPC_SHM_TYPE_APPL:
665c51a564aSJens Wiklander 		optee_rpc_cmd_free_suppl(ctx, shm);
666c51a564aSJens Wiklander 		break;
667c51a564aSJens Wiklander 	case OPTEE_RPC_SHM_TYPE_KERNEL:
668c51a564aSJens Wiklander 		tee_shm_free(shm);
669c51a564aSJens Wiklander 		break;
670c51a564aSJens Wiklander 	default:
671c51a564aSJens Wiklander 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
672c51a564aSJens Wiklander 	}
673c51a564aSJens Wiklander 	arg->ret = TEEC_SUCCESS;
674c51a564aSJens Wiklander }
675c51a564aSJens Wiklander 
handle_rpc_func_cmd_shm_alloc(struct tee_context * ctx,struct optee * optee,struct optee_msg_arg * arg,struct optee_call_ctx * call_ctx)676c51a564aSJens Wiklander static void handle_rpc_func_cmd_shm_alloc(struct tee_context *ctx,
677aceeafefSJens Wiklander 					  struct optee *optee,
678c51a564aSJens Wiklander 					  struct optee_msg_arg *arg,
679c51a564aSJens Wiklander 					  struct optee_call_ctx *call_ctx)
680c51a564aSJens Wiklander {
681c51a564aSJens Wiklander 	phys_addr_t pa;
682c51a564aSJens Wiklander 	struct tee_shm *shm;
683c51a564aSJens Wiklander 	size_t sz;
684c51a564aSJens Wiklander 	size_t n;
685c51a564aSJens Wiklander 
686c51a564aSJens Wiklander 	arg->ret_origin = TEEC_ORIGIN_COMMS;
687c51a564aSJens Wiklander 
688c51a564aSJens Wiklander 	if (!arg->num_params ||
689c51a564aSJens Wiklander 	    arg->params[0].attr != OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) {
690c51a564aSJens Wiklander 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
691c51a564aSJens Wiklander 		return;
692c51a564aSJens Wiklander 	}
693c51a564aSJens Wiklander 
694c51a564aSJens Wiklander 	for (n = 1; n < arg->num_params; n++) {
695c51a564aSJens Wiklander 		if (arg->params[n].attr != OPTEE_MSG_ATTR_TYPE_NONE) {
696c51a564aSJens Wiklander 			arg->ret = TEEC_ERROR_BAD_PARAMETERS;
697c51a564aSJens Wiklander 			return;
698c51a564aSJens Wiklander 		}
699c51a564aSJens Wiklander 	}
700c51a564aSJens Wiklander 
701c51a564aSJens Wiklander 	sz = arg->params[0].u.value.b;
702c51a564aSJens Wiklander 	switch (arg->params[0].u.value.a) {
703c51a564aSJens Wiklander 	case OPTEE_RPC_SHM_TYPE_APPL:
704c51a564aSJens Wiklander 		shm = optee_rpc_cmd_alloc_suppl(ctx, sz);
705c51a564aSJens Wiklander 		break;
706c51a564aSJens Wiklander 	case OPTEE_RPC_SHM_TYPE_KERNEL:
7075d41f1b3SJens Wiklander 		shm = tee_shm_alloc_priv_buf(optee->ctx, sz);
708c51a564aSJens Wiklander 		break;
709c51a564aSJens Wiklander 	default:
710c51a564aSJens Wiklander 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
711c51a564aSJens Wiklander 		return;
712c51a564aSJens Wiklander 	}
713c51a564aSJens Wiklander 
714c51a564aSJens Wiklander 	if (IS_ERR(shm)) {
715c51a564aSJens Wiklander 		arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
716c51a564aSJens Wiklander 		return;
717c51a564aSJens Wiklander 	}
718c51a564aSJens Wiklander 
719c51a564aSJens Wiklander 	if (tee_shm_get_pa(shm, 0, &pa)) {
720c51a564aSJens Wiklander 		arg->ret = TEEC_ERROR_BAD_PARAMETERS;
721c51a564aSJens Wiklander 		goto bad;
722c51a564aSJens Wiklander 	}
723c51a564aSJens Wiklander 
724c51a564aSJens Wiklander 	sz = tee_shm_get_size(shm);
725c51a564aSJens Wiklander 
726a45ea4efSJens Wiklander 	if (tee_shm_is_dynamic(shm)) {
727c51a564aSJens Wiklander 		struct page **pages;
728c51a564aSJens Wiklander 		u64 *pages_list;
729c51a564aSJens Wiklander 		size_t page_num;
730c51a564aSJens Wiklander 
731c51a564aSJens Wiklander 		pages = tee_shm_get_pages(shm, &page_num);
732c51a564aSJens Wiklander 		if (!pages || !page_num) {
733c51a564aSJens Wiklander 			arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
734c51a564aSJens Wiklander 			goto bad;
735c51a564aSJens Wiklander 		}
736c51a564aSJens Wiklander 
737c51a564aSJens Wiklander 		pages_list = optee_allocate_pages_list(page_num);
738c51a564aSJens Wiklander 		if (!pages_list) {
739c51a564aSJens Wiklander 			arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
740c51a564aSJens Wiklander 			goto bad;
741c51a564aSJens Wiklander 		}
742c51a564aSJens Wiklander 
743c51a564aSJens Wiklander 		call_ctx->pages_list = pages_list;
744c51a564aSJens Wiklander 		call_ctx->num_entries = page_num;
745c51a564aSJens Wiklander 
746c51a564aSJens Wiklander 		arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT |
747c51a564aSJens Wiklander 				      OPTEE_MSG_ATTR_NONCONTIG;
748c51a564aSJens Wiklander 		/*
749c51a564aSJens Wiklander 		 * In the least bits of u.tmem.buf_ptr we store buffer offset
750c51a564aSJens Wiklander 		 * from 4k page, as described in OP-TEE ABI.
751c51a564aSJens Wiklander 		 */
752c51a564aSJens Wiklander 		arg->params[0].u.tmem.buf_ptr = virt_to_phys(pages_list) |
753c51a564aSJens Wiklander 			(tee_shm_get_page_offset(shm) &
754c51a564aSJens Wiklander 			 (OPTEE_MSG_NONCONTIG_PAGE_SIZE - 1));
755c51a564aSJens Wiklander 		arg->params[0].u.tmem.size = tee_shm_get_size(shm);
756c51a564aSJens Wiklander 		arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
757c51a564aSJens Wiklander 
758c51a564aSJens Wiklander 		optee_fill_pages_list(pages_list, pages, page_num,
759c51a564aSJens Wiklander 				      tee_shm_get_page_offset(shm));
760c51a564aSJens Wiklander 	} else {
761c51a564aSJens Wiklander 		arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_TMEM_OUTPUT;
762c51a564aSJens Wiklander 		arg->params[0].u.tmem.buf_ptr = pa;
763c51a564aSJens Wiklander 		arg->params[0].u.tmem.size = sz;
764c51a564aSJens Wiklander 		arg->params[0].u.tmem.shm_ref = (unsigned long)shm;
765c51a564aSJens Wiklander 	}
766c51a564aSJens Wiklander 
767c51a564aSJens Wiklander 	arg->ret = TEEC_SUCCESS;
768c51a564aSJens Wiklander 	return;
769c51a564aSJens Wiklander bad:
770c51a564aSJens Wiklander 	tee_shm_free(shm);
771c51a564aSJens Wiklander }
772c51a564aSJens Wiklander 
free_pages_list(struct optee_call_ctx * call_ctx)773c51a564aSJens Wiklander static void free_pages_list(struct optee_call_ctx *call_ctx)
774c51a564aSJens Wiklander {
775c51a564aSJens Wiklander 	if (call_ctx->pages_list) {
776c51a564aSJens Wiklander 		optee_free_pages_list(call_ctx->pages_list,
777c51a564aSJens Wiklander 				      call_ctx->num_entries);
778c51a564aSJens Wiklander 		call_ctx->pages_list = NULL;
779c51a564aSJens Wiklander 		call_ctx->num_entries = 0;
780c51a564aSJens Wiklander 	}
781c51a564aSJens Wiklander }
782c51a564aSJens Wiklander 
optee_rpc_finalize_call(struct optee_call_ctx * call_ctx)783c51a564aSJens Wiklander static void optee_rpc_finalize_call(struct optee_call_ctx *call_ctx)
784c51a564aSJens Wiklander {
785c51a564aSJens Wiklander 	free_pages_list(call_ctx);
786c51a564aSJens Wiklander }
787c51a564aSJens Wiklander 
handle_rpc_func_cmd(struct tee_context * ctx,struct optee * optee,struct optee_msg_arg * arg,struct optee_call_ctx * call_ctx)788c51a564aSJens Wiklander static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee,
789ed8faf6cSJens Wiklander 				struct optee_msg_arg *arg,
790c51a564aSJens Wiklander 				struct optee_call_ctx *call_ctx)
791c51a564aSJens Wiklander {
792c51a564aSJens Wiklander 
793c51a564aSJens Wiklander 	switch (arg->cmd) {
794c51a564aSJens Wiklander 	case OPTEE_RPC_CMD_SHM_ALLOC:
795c51a564aSJens Wiklander 		free_pages_list(call_ctx);
796aceeafefSJens Wiklander 		handle_rpc_func_cmd_shm_alloc(ctx, optee, arg, call_ctx);
797c51a564aSJens Wiklander 		break;
798c51a564aSJens Wiklander 	case OPTEE_RPC_CMD_SHM_FREE:
799c51a564aSJens Wiklander 		handle_rpc_func_cmd_shm_free(ctx, arg);
800c51a564aSJens Wiklander 		break;
801c51a564aSJens Wiklander 	default:
802c51a564aSJens Wiklander 		optee_rpc_cmd(ctx, optee, arg);
803c51a564aSJens Wiklander 	}
804c51a564aSJens Wiklander }
805c51a564aSJens Wiklander 
806c51a564aSJens Wiklander /**
807c51a564aSJens Wiklander  * optee_handle_rpc() - handle RPC from secure world
808c51a564aSJens Wiklander  * @ctx:	context doing the RPC
809c51a564aSJens Wiklander  * @param:	value of registers for the RPC
810c51a564aSJens Wiklander  * @call_ctx:	call context. Preserved during one OP-TEE invocation
811c51a564aSJens Wiklander  *
812c51a564aSJens Wiklander  * Result of RPC is written back into @param.
813c51a564aSJens Wiklander  */
optee_handle_rpc(struct tee_context * ctx,struct optee_msg_arg * rpc_arg,struct optee_rpc_param * param,struct optee_call_ctx * call_ctx)814c51a564aSJens Wiklander static void optee_handle_rpc(struct tee_context *ctx,
815ed8faf6cSJens Wiklander 			     struct optee_msg_arg *rpc_arg,
816c51a564aSJens Wiklander 			     struct optee_rpc_param *param,
817c51a564aSJens Wiklander 			     struct optee_call_ctx *call_ctx)
818c51a564aSJens Wiklander {
819c51a564aSJens Wiklander 	struct tee_device *teedev = ctx->teedev;
820c51a564aSJens Wiklander 	struct optee *optee = tee_get_drvdata(teedev);
821ed8faf6cSJens Wiklander 	struct optee_msg_arg *arg;
822c51a564aSJens Wiklander 	struct tee_shm *shm;
823c51a564aSJens Wiklander 	phys_addr_t pa;
824c51a564aSJens Wiklander 
825c51a564aSJens Wiklander 	switch (OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0)) {
826c51a564aSJens Wiklander 	case OPTEE_SMC_RPC_FUNC_ALLOC:
8275d41f1b3SJens Wiklander 		shm = tee_shm_alloc_priv_buf(optee->ctx, param->a1);
828c51a564aSJens Wiklander 		if (!IS_ERR(shm) && !tee_shm_get_pa(shm, 0, &pa)) {
829c51a564aSJens Wiklander 			reg_pair_from_64(&param->a1, &param->a2, pa);
830c51a564aSJens Wiklander 			reg_pair_from_64(&param->a4, &param->a5,
831c51a564aSJens Wiklander 					 (unsigned long)shm);
832c51a564aSJens Wiklander 		} else {
833c51a564aSJens Wiklander 			param->a1 = 0;
834c51a564aSJens Wiklander 			param->a2 = 0;
835c51a564aSJens Wiklander 			param->a4 = 0;
836c51a564aSJens Wiklander 			param->a5 = 0;
837c51a564aSJens Wiklander 		}
8386add87fdSXiaolei Wang 		kmemleak_not_leak(shm);
839c51a564aSJens Wiklander 		break;
840c51a564aSJens Wiklander 	case OPTEE_SMC_RPC_FUNC_FREE:
841c51a564aSJens Wiklander 		shm = reg_pair_to_ptr(param->a1, param->a2);
842c51a564aSJens Wiklander 		tee_shm_free(shm);
843c51a564aSJens Wiklander 		break;
844c51a564aSJens Wiklander 	case OPTEE_SMC_RPC_FUNC_FOREIGN_INTR:
845c51a564aSJens Wiklander 		/*
846c51a564aSJens Wiklander 		 * A foreign interrupt was raised while secure world was
847c51a564aSJens Wiklander 		 * executing, since they are handled in Linux a dummy RPC is
848c51a564aSJens Wiklander 		 * performed to let Linux take the interrupt through the normal
849c51a564aSJens Wiklander 		 * vector.
850c51a564aSJens Wiklander 		 */
851c51a564aSJens Wiklander 		break;
852c51a564aSJens Wiklander 	case OPTEE_SMC_RPC_FUNC_CMD:
853ed8faf6cSJens Wiklander 		if (rpc_arg) {
854ed8faf6cSJens Wiklander 			arg = rpc_arg;
855ed8faf6cSJens Wiklander 		} else {
856c51a564aSJens Wiklander 			shm = reg_pair_to_ptr(param->a1, param->a2);
857ed8faf6cSJens Wiklander 			arg = tee_shm_get_va(shm, 0);
858ed8faf6cSJens Wiklander 			if (IS_ERR(arg)) {
859ed8faf6cSJens Wiklander 				pr_err("%s: tee_shm_get_va %p failed\n",
860ed8faf6cSJens Wiklander 				       __func__, shm);
861ed8faf6cSJens Wiklander 				break;
862ed8faf6cSJens Wiklander 			}
863ed8faf6cSJens Wiklander 		}
864ed8faf6cSJens Wiklander 
865ed8faf6cSJens Wiklander 		handle_rpc_func_cmd(ctx, optee, arg, call_ctx);
866c51a564aSJens Wiklander 		break;
867c51a564aSJens Wiklander 	default:
868c51a564aSJens Wiklander 		pr_warn("Unknown RPC func 0x%x\n",
869c51a564aSJens Wiklander 			(u32)OPTEE_SMC_RETURN_GET_RPC_FUNC(param->a0));
870c51a564aSJens Wiklander 		break;
871c51a564aSJens Wiklander 	}
872c51a564aSJens Wiklander 
873c51a564aSJens Wiklander 	param->a0 = OPTEE_SMC_CALL_RETURN_FROM_RPC;
874c51a564aSJens Wiklander }
875c51a564aSJens Wiklander 
876c51a564aSJens Wiklander /**
877c51a564aSJens Wiklander  * optee_smc_do_call_with_arg() - Do an SMC to OP-TEE in secure world
878c51a564aSJens Wiklander  * @ctx:	calling context
879ed8faf6cSJens Wiklander  * @shm:	shared memory holding the message to pass to secure world
8805b4018b9SJens Wiklander  * @offs:	offset of the message in @shm
881c51a564aSJens Wiklander  *
882c51a564aSJens Wiklander  * Does and SMC to OP-TEE in secure world and handles eventual resulting
883c51a564aSJens Wiklander  * Remote Procedure Calls (RPC) from OP-TEE.
884c51a564aSJens Wiklander  *
885c51a564aSJens Wiklander  * Returns return code from secure world, 0 is OK
886c51a564aSJens Wiklander  */
optee_smc_do_call_with_arg(struct tee_context * ctx,struct tee_shm * shm,u_int offs)887c51a564aSJens Wiklander static int optee_smc_do_call_with_arg(struct tee_context *ctx,
8885b4018b9SJens Wiklander 				      struct tee_shm *shm, u_int offs)
889c51a564aSJens Wiklander {
890c51a564aSJens Wiklander 	struct optee *optee = tee_get_drvdata(ctx->teedev);
891c51a564aSJens Wiklander 	struct optee_call_waiter w;
892c51a564aSJens Wiklander 	struct optee_rpc_param param = { };
893c51a564aSJens Wiklander 	struct optee_call_ctx call_ctx = { };
894ed8faf6cSJens Wiklander 	struct optee_msg_arg *rpc_arg = NULL;
895c51a564aSJens Wiklander 	int rc;
896c51a564aSJens Wiklander 
897ed8faf6cSJens Wiklander 	if (optee->rpc_param_count) {
898ed8faf6cSJens Wiklander 		struct optee_msg_arg *arg;
899ed8faf6cSJens Wiklander 		unsigned int rpc_arg_offs;
900ed8faf6cSJens Wiklander 
9015b4018b9SJens Wiklander 		arg = tee_shm_get_va(shm, offs);
902ed8faf6cSJens Wiklander 		if (IS_ERR(arg))
903ed8faf6cSJens Wiklander 			return PTR_ERR(arg);
904ed8faf6cSJens Wiklander 
905ed8faf6cSJens Wiklander 		rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
9065b4018b9SJens Wiklander 		rpc_arg = tee_shm_get_va(shm, offs + rpc_arg_offs);
907d4fac258SYang Yingliang 		if (IS_ERR(rpc_arg))
908d4fac258SYang Yingliang 			return PTR_ERR(rpc_arg);
909ed8faf6cSJens Wiklander 	}
910ed8faf6cSJens Wiklander 
911ed8faf6cSJens Wiklander 	if  (rpc_arg && tee_shm_is_dynamic(shm)) {
912ed8faf6cSJens Wiklander 		param.a0 = OPTEE_SMC_CALL_WITH_REGD_ARG;
913ed8faf6cSJens Wiklander 		reg_pair_from_64(&param.a1, &param.a2, (u_long)shm);
9145b4018b9SJens Wiklander 		param.a3 = offs;
915ed8faf6cSJens Wiklander 	} else {
916ed8faf6cSJens Wiklander 		phys_addr_t parg;
917ed8faf6cSJens Wiklander 
9185b4018b9SJens Wiklander 		rc = tee_shm_get_pa(shm, offs, &parg);
919c51a564aSJens Wiklander 		if (rc)
920c51a564aSJens Wiklander 			return rc;
921c51a564aSJens Wiklander 
922ed8faf6cSJens Wiklander 		if (rpc_arg)
923ed8faf6cSJens Wiklander 			param.a0 = OPTEE_SMC_CALL_WITH_RPC_ARG;
924ed8faf6cSJens Wiklander 		else
925c51a564aSJens Wiklander 			param.a0 = OPTEE_SMC_CALL_WITH_ARG;
926c51a564aSJens Wiklander 		reg_pair_from_64(&param.a1, &param.a2, parg);
927ed8faf6cSJens Wiklander 	}
928c51a564aSJens Wiklander 	/* Initialize waiter */
929c51a564aSJens Wiklander 	optee_cq_wait_init(&optee->call_queue, &w);
930c51a564aSJens Wiklander 	while (true) {
931c51a564aSJens Wiklander 		struct arm_smccc_res res;
932c51a564aSJens Wiklander 
933c51a564aSJens Wiklander 		trace_optee_invoke_fn_begin(&param);
934c51a564aSJens Wiklander 		optee->smc.invoke_fn(param.a0, param.a1, param.a2, param.a3,
935c51a564aSJens Wiklander 				     param.a4, param.a5, param.a6, param.a7,
936c51a564aSJens Wiklander 				     &res);
937c51a564aSJens Wiklander 		trace_optee_invoke_fn_end(&param, &res);
938c51a564aSJens Wiklander 
939c51a564aSJens Wiklander 		if (res.a0 == OPTEE_SMC_RETURN_ETHREAD_LIMIT) {
940c51a564aSJens Wiklander 			/*
941c51a564aSJens Wiklander 			 * Out of threads in secure world, wait for a thread
942c51a564aSJens Wiklander 			 * become available.
943c51a564aSJens Wiklander 			 */
944c51a564aSJens Wiklander 			optee_cq_wait_for_completion(&optee->call_queue, &w);
945c51a564aSJens Wiklander 		} else if (OPTEE_SMC_RETURN_IS_RPC(res.a0)) {
946c51a564aSJens Wiklander 			cond_resched();
947c51a564aSJens Wiklander 			param.a0 = res.a0;
948c51a564aSJens Wiklander 			param.a1 = res.a1;
949c51a564aSJens Wiklander 			param.a2 = res.a2;
950c51a564aSJens Wiklander 			param.a3 = res.a3;
951ed8faf6cSJens Wiklander 			optee_handle_rpc(ctx, rpc_arg, &param, &call_ctx);
952c51a564aSJens Wiklander 		} else {
953c51a564aSJens Wiklander 			rc = res.a0;
954c51a564aSJens Wiklander 			break;
955c51a564aSJens Wiklander 		}
956c51a564aSJens Wiklander 	}
957c51a564aSJens Wiklander 
958c51a564aSJens Wiklander 	optee_rpc_finalize_call(&call_ctx);
959c51a564aSJens Wiklander 	/*
960c51a564aSJens Wiklander 	 * We're done with our thread in secure world, if there's any
961c51a564aSJens Wiklander 	 * thread waiters wake up one.
962c51a564aSJens Wiklander 	 */
963c51a564aSJens Wiklander 	optee_cq_wait_final(&optee->call_queue, &w);
964c51a564aSJens Wiklander 
965c51a564aSJens Wiklander 	return rc;
966c51a564aSJens Wiklander }
967c51a564aSJens Wiklander 
simple_call_with_arg(struct tee_context * ctx,u32 cmd)9686749e69cSJens Wiklander static int simple_call_with_arg(struct tee_context *ctx, u32 cmd)
9696749e69cSJens Wiklander {
9705b4018b9SJens Wiklander 	struct optee_shm_arg_entry *entry;
9716749e69cSJens Wiklander 	struct optee_msg_arg *msg_arg;
9726749e69cSJens Wiklander 	struct tee_shm *shm;
9735b4018b9SJens Wiklander 	u_int offs;
9746749e69cSJens Wiklander 
9755b4018b9SJens Wiklander 	msg_arg = optee_get_msg_arg(ctx, 0, &entry, &shm, &offs);
9765b4018b9SJens Wiklander 	if (IS_ERR(msg_arg))
9775b4018b9SJens Wiklander 		return PTR_ERR(msg_arg);
9786749e69cSJens Wiklander 
9796749e69cSJens Wiklander 	msg_arg->cmd = cmd;
9805b4018b9SJens Wiklander 	optee_smc_do_call_with_arg(ctx, shm, offs);
9816749e69cSJens Wiklander 
9825b4018b9SJens Wiklander 	optee_free_msg_arg(ctx, entry, offs);
9836749e69cSJens Wiklander 	return 0;
9846749e69cSJens Wiklander }
9856749e69cSJens Wiklander 
optee_smc_do_bottom_half(struct tee_context * ctx)9866749e69cSJens Wiklander static int optee_smc_do_bottom_half(struct tee_context *ctx)
9876749e69cSJens Wiklander {
9886749e69cSJens Wiklander 	return simple_call_with_arg(ctx, OPTEE_MSG_CMD_DO_BOTTOM_HALF);
9896749e69cSJens Wiklander }
9906749e69cSJens Wiklander 
optee_smc_stop_async_notif(struct tee_context * ctx)9916749e69cSJens Wiklander static int optee_smc_stop_async_notif(struct tee_context *ctx)
9926749e69cSJens Wiklander {
9936749e69cSJens Wiklander 	return simple_call_with_arg(ctx, OPTEE_MSG_CMD_STOP_ASYNC_NOTIF);
9946749e69cSJens Wiklander }
9956749e69cSJens Wiklander 
996c51a564aSJens Wiklander /*
9976749e69cSJens Wiklander  * 5. Asynchronous notification
9986749e69cSJens Wiklander  */
9996749e69cSJens Wiklander 
get_async_notif_value(optee_invoke_fn * invoke_fn,bool * value_valid,bool * value_pending)10006749e69cSJens Wiklander static u32 get_async_notif_value(optee_invoke_fn *invoke_fn, bool *value_valid,
10016749e69cSJens Wiklander 				 bool *value_pending)
10026749e69cSJens Wiklander {
10036749e69cSJens Wiklander 	struct arm_smccc_res res;
10046749e69cSJens Wiklander 
10056749e69cSJens Wiklander 	invoke_fn(OPTEE_SMC_GET_ASYNC_NOTIF_VALUE, 0, 0, 0, 0, 0, 0, 0, &res);
10066749e69cSJens Wiklander 
1007*654d0310SEtienne Carriere 	if (res.a0) {
1008*654d0310SEtienne Carriere 		*value_valid = false;
10096749e69cSJens Wiklander 		return 0;
1010*654d0310SEtienne Carriere 	}
10116749e69cSJens Wiklander 	*value_valid = (res.a2 & OPTEE_SMC_ASYNC_NOTIF_VALUE_VALID);
10126749e69cSJens Wiklander 	*value_pending = (res.a2 & OPTEE_SMC_ASYNC_NOTIF_VALUE_PENDING);
10136749e69cSJens Wiklander 	return res.a1;
10146749e69cSJens Wiklander }
10156749e69cSJens Wiklander 
irq_handler(struct optee * optee)1016b3b4ced1SEtienne Carriere static irqreturn_t irq_handler(struct optee *optee)
10176749e69cSJens Wiklander {
10186749e69cSJens Wiklander 	bool do_bottom_half = false;
10196749e69cSJens Wiklander 	bool value_valid;
10206749e69cSJens Wiklander 	bool value_pending;
10216749e69cSJens Wiklander 	u32 value;
10226749e69cSJens Wiklander 
10236749e69cSJens Wiklander 	do {
10246749e69cSJens Wiklander 		value = get_async_notif_value(optee->smc.invoke_fn,
10256749e69cSJens Wiklander 					      &value_valid, &value_pending);
10266749e69cSJens Wiklander 		if (!value_valid)
10276749e69cSJens Wiklander 			break;
10286749e69cSJens Wiklander 
10296749e69cSJens Wiklander 		if (value == OPTEE_SMC_ASYNC_NOTIF_VALUE_DO_BOTTOM_HALF)
10306749e69cSJens Wiklander 			do_bottom_half = true;
10316749e69cSJens Wiklander 		else
10326749e69cSJens Wiklander 			optee_notif_send(optee, value);
10336749e69cSJens Wiklander 	} while (value_pending);
10346749e69cSJens Wiklander 
10356749e69cSJens Wiklander 	if (do_bottom_half)
10366749e69cSJens Wiklander 		return IRQ_WAKE_THREAD;
10376749e69cSJens Wiklander 	return IRQ_HANDLED;
10386749e69cSJens Wiklander }
10396749e69cSJens Wiklander 
notif_irq_handler(int irq,void * dev_id)1040b3b4ced1SEtienne Carriere static irqreturn_t notif_irq_handler(int irq, void *dev_id)
1041b3b4ced1SEtienne Carriere {
1042b3b4ced1SEtienne Carriere 	struct optee *optee = dev_id;
1043b3b4ced1SEtienne Carriere 
1044b3b4ced1SEtienne Carriere 	return irq_handler(optee);
1045b3b4ced1SEtienne Carriere }
1046b3b4ced1SEtienne Carriere 
notif_irq_thread_fn(int irq,void * dev_id)10476749e69cSJens Wiklander static irqreturn_t notif_irq_thread_fn(int irq, void *dev_id)
10486749e69cSJens Wiklander {
10496749e69cSJens Wiklander 	struct optee *optee = dev_id;
10506749e69cSJens Wiklander 
1051aceeafefSJens Wiklander 	optee_smc_do_bottom_half(optee->ctx);
10526749e69cSJens Wiklander 
10536749e69cSJens Wiklander 	return IRQ_HANDLED;
10546749e69cSJens Wiklander }
10556749e69cSJens Wiklander 
init_irq(struct optee * optee,u_int irq)1056b3b4ced1SEtienne Carriere static int init_irq(struct optee *optee, u_int irq)
10576749e69cSJens Wiklander {
10586749e69cSJens Wiklander 	int rc;
10596749e69cSJens Wiklander 
10606749e69cSJens Wiklander 	rc = request_threaded_irq(irq, notif_irq_handler,
10616749e69cSJens Wiklander 				  notif_irq_thread_fn,
10626749e69cSJens Wiklander 				  0, "optee_notification", optee);
10636749e69cSJens Wiklander 	if (rc)
1064aceeafefSJens Wiklander 		return rc;
10656749e69cSJens Wiklander 
10666749e69cSJens Wiklander 	optee->smc.notif_irq = irq;
10676749e69cSJens Wiklander 
10686749e69cSJens Wiklander 	return 0;
10696749e69cSJens Wiklander }
10706749e69cSJens Wiklander 
notif_pcpu_irq_handler(int irq,void * dev_id)1071b3b4ced1SEtienne Carriere static irqreturn_t notif_pcpu_irq_handler(int irq, void *dev_id)
1072b3b4ced1SEtienne Carriere {
1073b3b4ced1SEtienne Carriere 	struct optee_pcpu *pcpu = dev_id;
1074b3b4ced1SEtienne Carriere 	struct optee *optee = pcpu->optee;
1075b3b4ced1SEtienne Carriere 
1076b3b4ced1SEtienne Carriere 	if (irq_handler(optee) == IRQ_WAKE_THREAD)
1077b3b4ced1SEtienne Carriere 		queue_work(optee->smc.notif_pcpu_wq,
1078b3b4ced1SEtienne Carriere 			   &optee->smc.notif_pcpu_work);
1079b3b4ced1SEtienne Carriere 
1080b3b4ced1SEtienne Carriere 	return IRQ_HANDLED;
1081b3b4ced1SEtienne Carriere }
1082b3b4ced1SEtienne Carriere 
notif_pcpu_irq_work_fn(struct work_struct * work)1083b3b4ced1SEtienne Carriere static void notif_pcpu_irq_work_fn(struct work_struct *work)
1084b3b4ced1SEtienne Carriere {
1085b3b4ced1SEtienne Carriere 	struct optee_smc *optee_smc = container_of(work, struct optee_smc,
1086b3b4ced1SEtienne Carriere 						   notif_pcpu_work);
1087b3b4ced1SEtienne Carriere 	struct optee *optee = container_of(optee_smc, struct optee, smc);
1088b3b4ced1SEtienne Carriere 
1089b3b4ced1SEtienne Carriere 	optee_smc_do_bottom_half(optee->ctx);
1090b3b4ced1SEtienne Carriere }
1091b3b4ced1SEtienne Carriere 
init_pcpu_irq(struct optee * optee,u_int irq)1092b3b4ced1SEtienne Carriere static int init_pcpu_irq(struct optee *optee, u_int irq)
1093b3b4ced1SEtienne Carriere {
1094b3b4ced1SEtienne Carriere 	struct optee_pcpu __percpu *optee_pcpu;
1095b3b4ced1SEtienne Carriere 	int cpu, rc;
1096b3b4ced1SEtienne Carriere 
1097b3b4ced1SEtienne Carriere 	optee_pcpu = alloc_percpu(struct optee_pcpu);
1098b3b4ced1SEtienne Carriere 	if (!optee_pcpu)
1099b3b4ced1SEtienne Carriere 		return -ENOMEM;
1100b3b4ced1SEtienne Carriere 
1101b3b4ced1SEtienne Carriere 	for_each_present_cpu(cpu)
1102b3b4ced1SEtienne Carriere 		per_cpu_ptr(optee_pcpu, cpu)->optee = optee;
1103b3b4ced1SEtienne Carriere 
1104b3b4ced1SEtienne Carriere 	rc = request_percpu_irq(irq, notif_pcpu_irq_handler,
1105b3b4ced1SEtienne Carriere 				"optee_pcpu_notification", optee_pcpu);
1106b3b4ced1SEtienne Carriere 	if (rc)
1107b3b4ced1SEtienne Carriere 		goto err_free_pcpu;
1108b3b4ced1SEtienne Carriere 
1109b3b4ced1SEtienne Carriere 	INIT_WORK(&optee->smc.notif_pcpu_work, notif_pcpu_irq_work_fn);
1110b3b4ced1SEtienne Carriere 	optee->smc.notif_pcpu_wq = create_workqueue("optee_pcpu_notification");
1111b3b4ced1SEtienne Carriere 	if (!optee->smc.notif_pcpu_wq) {
1112b3b4ced1SEtienne Carriere 		rc = -EINVAL;
1113b3b4ced1SEtienne Carriere 		goto err_free_pcpu_irq;
1114b3b4ced1SEtienne Carriere 	}
1115b3b4ced1SEtienne Carriere 
1116b3b4ced1SEtienne Carriere 	optee->smc.optee_pcpu = optee_pcpu;
1117b3b4ced1SEtienne Carriere 	optee->smc.notif_irq = irq;
1118b3b4ced1SEtienne Carriere 
1119b3b4ced1SEtienne Carriere 	pcpu_irq_num = irq;
1120b3b4ced1SEtienne Carriere 	rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee/pcpu-notif:starting",
1121b3b4ced1SEtienne Carriere 			       optee_cpuhp_enable_pcpu_irq,
1122b3b4ced1SEtienne Carriere 			       optee_cpuhp_disable_pcpu_irq);
1123b3b4ced1SEtienne Carriere 	if (!rc)
1124b3b4ced1SEtienne Carriere 		rc = -EINVAL;
1125b3b4ced1SEtienne Carriere 	if (rc < 0)
1126b3b4ced1SEtienne Carriere 		goto err_free_pcpu_irq;
1127b3b4ced1SEtienne Carriere 
1128b3b4ced1SEtienne Carriere 	optee->smc.notif_cpuhp_state = rc;
1129b3b4ced1SEtienne Carriere 
1130b3b4ced1SEtienne Carriere 	return 0;
1131b3b4ced1SEtienne Carriere 
1132b3b4ced1SEtienne Carriere err_free_pcpu_irq:
1133b3b4ced1SEtienne Carriere 	free_percpu_irq(irq, optee_pcpu);
1134b3b4ced1SEtienne Carriere err_free_pcpu:
1135b3b4ced1SEtienne Carriere 	free_percpu(optee_pcpu);
1136b3b4ced1SEtienne Carriere 
1137b3b4ced1SEtienne Carriere 	return rc;
1138b3b4ced1SEtienne Carriere }
1139b3b4ced1SEtienne Carriere 
optee_smc_notif_init_irq(struct optee * optee,u_int irq)1140b3b4ced1SEtienne Carriere static int optee_smc_notif_init_irq(struct optee *optee, u_int irq)
1141b3b4ced1SEtienne Carriere {
1142b3b4ced1SEtienne Carriere 	if (irq_is_percpu_devid(irq))
1143b3b4ced1SEtienne Carriere 		return init_pcpu_irq(optee, irq);
1144b3b4ced1SEtienne Carriere 	else
1145b3b4ced1SEtienne Carriere 		return init_irq(optee, irq);
1146b3b4ced1SEtienne Carriere }
1147b3b4ced1SEtienne Carriere 
uninit_pcpu_irq(struct optee * optee)1148b3b4ced1SEtienne Carriere static void uninit_pcpu_irq(struct optee *optee)
1149b3b4ced1SEtienne Carriere {
1150b3b4ced1SEtienne Carriere 	cpuhp_remove_state(optee->smc.notif_cpuhp_state);
1151b3b4ced1SEtienne Carriere 
1152b3b4ced1SEtienne Carriere 	destroy_workqueue(optee->smc.notif_pcpu_wq);
1153b3b4ced1SEtienne Carriere 
1154b3b4ced1SEtienne Carriere 	free_percpu_irq(optee->smc.notif_irq, optee->smc.optee_pcpu);
1155b3b4ced1SEtienne Carriere 	free_percpu(optee->smc.optee_pcpu);
1156b3b4ced1SEtienne Carriere }
1157b3b4ced1SEtienne Carriere 
optee_smc_notif_uninit_irq(struct optee * optee)11586749e69cSJens Wiklander static void optee_smc_notif_uninit_irq(struct optee *optee)
11596749e69cSJens Wiklander {
1160aceeafefSJens Wiklander 	if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
1161aceeafefSJens Wiklander 		optee_smc_stop_async_notif(optee->ctx);
11626749e69cSJens Wiklander 		if (optee->smc.notif_irq) {
1163b3b4ced1SEtienne Carriere 			if (irq_is_percpu_devid(optee->smc.notif_irq))
1164b3b4ced1SEtienne Carriere 				uninit_pcpu_irq(optee);
1165b3b4ced1SEtienne Carriere 			else
11666749e69cSJens Wiklander 				free_irq(optee->smc.notif_irq, optee);
1167b3b4ced1SEtienne Carriere 
11686749e69cSJens Wiklander 			irq_dispose_mapping(optee->smc.notif_irq);
11696749e69cSJens Wiklander 		}
11706749e69cSJens Wiklander 	}
11716749e69cSJens Wiklander }
11726749e69cSJens Wiklander 
11736749e69cSJens Wiklander /*
11746749e69cSJens Wiklander  * 6. Driver initialization
11756749e69cSJens Wiklander  *
11766749e69cSJens Wiklander  * During driver initialization is secure world probed to find out which
1177c51a564aSJens Wiklander  * features it supports so the driver can be initialized with a matching
1178c51a564aSJens Wiklander  * configuration. This involves for instance support for dynamic shared
1179c51a564aSJens Wiklander  * memory instead of a static memory carvout.
1180c51a564aSJens Wiklander  */
1181c51a564aSJens Wiklander 
optee_get_version(struct tee_device * teedev,struct tee_ioctl_version_data * vers)1182c51a564aSJens Wiklander static void optee_get_version(struct tee_device *teedev,
1183c51a564aSJens Wiklander 			      struct tee_ioctl_version_data *vers)
1184c51a564aSJens Wiklander {
1185c51a564aSJens Wiklander 	struct tee_ioctl_version_data v = {
1186c51a564aSJens Wiklander 		.impl_id = TEE_IMPL_ID_OPTEE,
1187c51a564aSJens Wiklander 		.impl_caps = TEE_OPTEE_CAP_TZ,
1188c51a564aSJens Wiklander 		.gen_caps = TEE_GEN_CAP_GP,
1189c51a564aSJens Wiklander 	};
1190c51a564aSJens Wiklander 	struct optee *optee = tee_get_drvdata(teedev);
1191c51a564aSJens Wiklander 
1192c51a564aSJens Wiklander 	if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
1193c51a564aSJens Wiklander 		v.gen_caps |= TEE_GEN_CAP_REG_MEM;
1194c51a564aSJens Wiklander 	if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL)
1195c51a564aSJens Wiklander 		v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL;
1196c51a564aSJens Wiklander 	*vers = v;
1197c51a564aSJens Wiklander }
1198c51a564aSJens Wiklander 
optee_smc_open(struct tee_context * ctx)1199c51a564aSJens Wiklander static int optee_smc_open(struct tee_context *ctx)
1200c51a564aSJens Wiklander {
1201c51a564aSJens Wiklander 	struct optee *optee = tee_get_drvdata(ctx->teedev);
1202c51a564aSJens Wiklander 	u32 sec_caps = optee->smc.sec_caps;
1203c51a564aSJens Wiklander 
1204c51a564aSJens Wiklander 	return optee_open(ctx, sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL);
1205c51a564aSJens Wiklander }
1206c51a564aSJens Wiklander 
1207c51a564aSJens Wiklander static const struct tee_driver_ops optee_clnt_ops = {
1208c51a564aSJens Wiklander 	.get_version = optee_get_version,
1209c51a564aSJens Wiklander 	.open = optee_smc_open,
1210c51a564aSJens Wiklander 	.release = optee_release,
1211c51a564aSJens Wiklander 	.open_session = optee_open_session,
1212c51a564aSJens Wiklander 	.close_session = optee_close_session,
1213c51a564aSJens Wiklander 	.invoke_func = optee_invoke_func,
1214c51a564aSJens Wiklander 	.cancel_req = optee_cancel_req,
1215c51a564aSJens Wiklander 	.shm_register = optee_shm_register,
1216c51a564aSJens Wiklander 	.shm_unregister = optee_shm_unregister,
1217c51a564aSJens Wiklander };
1218c51a564aSJens Wiklander 
1219c51a564aSJens Wiklander static const struct tee_desc optee_clnt_desc = {
1220c51a564aSJens Wiklander 	.name = DRIVER_NAME "-clnt",
1221c51a564aSJens Wiklander 	.ops = &optee_clnt_ops,
1222c51a564aSJens Wiklander 	.owner = THIS_MODULE,
1223c51a564aSJens Wiklander };
1224c51a564aSJens Wiklander 
1225c51a564aSJens Wiklander static const struct tee_driver_ops optee_supp_ops = {
1226c51a564aSJens Wiklander 	.get_version = optee_get_version,
1227c51a564aSJens Wiklander 	.open = optee_smc_open,
1228c51a564aSJens Wiklander 	.release = optee_release_supp,
1229c51a564aSJens Wiklander 	.supp_recv = optee_supp_recv,
1230c51a564aSJens Wiklander 	.supp_send = optee_supp_send,
1231c51a564aSJens Wiklander 	.shm_register = optee_shm_register_supp,
1232c51a564aSJens Wiklander 	.shm_unregister = optee_shm_unregister_supp,
1233c51a564aSJens Wiklander };
1234c51a564aSJens Wiklander 
1235c51a564aSJens Wiklander static const struct tee_desc optee_supp_desc = {
1236c51a564aSJens Wiklander 	.name = DRIVER_NAME "-supp",
1237c51a564aSJens Wiklander 	.ops = &optee_supp_ops,
1238c51a564aSJens Wiklander 	.owner = THIS_MODULE,
1239c51a564aSJens Wiklander 	.flags = TEE_DESC_PRIVILEGED,
1240c51a564aSJens Wiklander };
1241c51a564aSJens Wiklander 
1242c51a564aSJens Wiklander static const struct optee_ops optee_ops = {
1243c51a564aSJens Wiklander 	.do_call_with_arg = optee_smc_do_call_with_arg,
1244c51a564aSJens Wiklander 	.to_msg_param = optee_to_msg_param,
1245c51a564aSJens Wiklander 	.from_msg_param = optee_from_msg_param,
1246c51a564aSJens Wiklander };
1247c51a564aSJens Wiklander 
enable_async_notif(optee_invoke_fn * invoke_fn)12486749e69cSJens Wiklander static int enable_async_notif(optee_invoke_fn *invoke_fn)
12496749e69cSJens Wiklander {
12506749e69cSJens Wiklander 	struct arm_smccc_res res;
12516749e69cSJens Wiklander 
12526749e69cSJens Wiklander 	invoke_fn(OPTEE_SMC_ENABLE_ASYNC_NOTIF, 0, 0, 0, 0, 0, 0, 0, &res);
12536749e69cSJens Wiklander 
12546749e69cSJens Wiklander 	if (res.a0)
12556749e69cSJens Wiklander 		return -EINVAL;
12566749e69cSJens Wiklander 	return 0;
12576749e69cSJens Wiklander }
12586749e69cSJens Wiklander 
optee_msg_api_uid_is_optee_api(optee_invoke_fn * invoke_fn)1259c51a564aSJens Wiklander static bool optee_msg_api_uid_is_optee_api(optee_invoke_fn *invoke_fn)
1260c51a564aSJens Wiklander {
1261c51a564aSJens Wiklander 	struct arm_smccc_res res;
1262c51a564aSJens Wiklander 
1263c51a564aSJens Wiklander 	invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
1264c51a564aSJens Wiklander 
1265c51a564aSJens Wiklander 	if (res.a0 == OPTEE_MSG_UID_0 && res.a1 == OPTEE_MSG_UID_1 &&
1266c51a564aSJens Wiklander 	    res.a2 == OPTEE_MSG_UID_2 && res.a3 == OPTEE_MSG_UID_3)
1267c51a564aSJens Wiklander 		return true;
1268c51a564aSJens Wiklander 	return false;
1269c51a564aSJens Wiklander }
1270c51a564aSJens Wiklander 
1271f3040daaSJeffrey Kardatzke #ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE
optee_msg_api_uid_is_optee_image_load(optee_invoke_fn * invoke_fn)1272f3040daaSJeffrey Kardatzke static bool optee_msg_api_uid_is_optee_image_load(optee_invoke_fn *invoke_fn)
1273f3040daaSJeffrey Kardatzke {
1274f3040daaSJeffrey Kardatzke 	struct arm_smccc_res res;
1275f3040daaSJeffrey Kardatzke 
1276f3040daaSJeffrey Kardatzke 	invoke_fn(OPTEE_SMC_CALLS_UID, 0, 0, 0, 0, 0, 0, 0, &res);
1277f3040daaSJeffrey Kardatzke 
1278f3040daaSJeffrey Kardatzke 	if (res.a0 == OPTEE_MSG_IMAGE_LOAD_UID_0 &&
1279f3040daaSJeffrey Kardatzke 	    res.a1 == OPTEE_MSG_IMAGE_LOAD_UID_1 &&
1280f3040daaSJeffrey Kardatzke 	    res.a2 == OPTEE_MSG_IMAGE_LOAD_UID_2 &&
1281f3040daaSJeffrey Kardatzke 	    res.a3 == OPTEE_MSG_IMAGE_LOAD_UID_3)
1282f3040daaSJeffrey Kardatzke 		return true;
1283f3040daaSJeffrey Kardatzke 	return false;
1284f3040daaSJeffrey Kardatzke }
1285f3040daaSJeffrey Kardatzke #endif
1286f3040daaSJeffrey Kardatzke 
optee_msg_get_os_revision(optee_invoke_fn * invoke_fn)1287c51a564aSJens Wiklander static void optee_msg_get_os_revision(optee_invoke_fn *invoke_fn)
1288c51a564aSJens Wiklander {
1289c51a564aSJens Wiklander 	union {
1290c51a564aSJens Wiklander 		struct arm_smccc_res smccc;
1291c51a564aSJens Wiklander 		struct optee_smc_call_get_os_revision_result result;
1292c51a564aSJens Wiklander 	} res = {
1293c51a564aSJens Wiklander 		.result = {
1294c51a564aSJens Wiklander 			.build_id = 0
1295c51a564aSJens Wiklander 		}
1296c51a564aSJens Wiklander 	};
1297c51a564aSJens Wiklander 
1298c51a564aSJens Wiklander 	invoke_fn(OPTEE_SMC_CALL_GET_OS_REVISION, 0, 0, 0, 0, 0, 0, 0,
1299c51a564aSJens Wiklander 		  &res.smccc);
1300c51a564aSJens Wiklander 
1301c51a564aSJens Wiklander 	if (res.result.build_id)
1302c51a564aSJens Wiklander 		pr_info("revision %lu.%lu (%08lx)", res.result.major,
1303c51a564aSJens Wiklander 			res.result.minor, res.result.build_id);
1304c51a564aSJens Wiklander 	else
1305c51a564aSJens Wiklander 		pr_info("revision %lu.%lu", res.result.major, res.result.minor);
1306c51a564aSJens Wiklander }
1307c51a564aSJens Wiklander 
optee_msg_api_revision_is_compatible(optee_invoke_fn * invoke_fn)1308c51a564aSJens Wiklander static bool optee_msg_api_revision_is_compatible(optee_invoke_fn *invoke_fn)
1309c51a564aSJens Wiklander {
1310c51a564aSJens Wiklander 	union {
1311c51a564aSJens Wiklander 		struct arm_smccc_res smccc;
1312c51a564aSJens Wiklander 		struct optee_smc_calls_revision_result result;
1313c51a564aSJens Wiklander 	} res;
1314c51a564aSJens Wiklander 
1315c51a564aSJens Wiklander 	invoke_fn(OPTEE_SMC_CALLS_REVISION, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
1316c51a564aSJens Wiklander 
1317c51a564aSJens Wiklander 	if (res.result.major == OPTEE_MSG_REVISION_MAJOR &&
1318c51a564aSJens Wiklander 	    (int)res.result.minor >= OPTEE_MSG_REVISION_MINOR)
1319c51a564aSJens Wiklander 		return true;
1320c51a564aSJens Wiklander 	return false;
1321c51a564aSJens Wiklander }
1322c51a564aSJens Wiklander 
optee_msg_exchange_capabilities(optee_invoke_fn * invoke_fn,u32 * sec_caps,u32 * max_notif_value,unsigned int * rpc_param_count)1323c51a564aSJens Wiklander static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
1324ed8faf6cSJens Wiklander 					    u32 *sec_caps, u32 *max_notif_value,
1325ed8faf6cSJens Wiklander 					    unsigned int *rpc_param_count)
1326c51a564aSJens Wiklander {
1327c51a564aSJens Wiklander 	union {
1328c51a564aSJens Wiklander 		struct arm_smccc_res smccc;
1329c51a564aSJens Wiklander 		struct optee_smc_exchange_capabilities_result result;
1330c51a564aSJens Wiklander 	} res;
1331c51a564aSJens Wiklander 	u32 a1 = 0;
1332c51a564aSJens Wiklander 
1333c51a564aSJens Wiklander 	/*
1334c51a564aSJens Wiklander 	 * TODO This isn't enough to tell if it's UP system (from kernel
1335c51a564aSJens Wiklander 	 * point of view) or not, is_smp() returns the information
1336c51a564aSJens Wiklander 	 * needed, but can't be called directly from here.
1337c51a564aSJens Wiklander 	 */
1338c51a564aSJens Wiklander 	if (!IS_ENABLED(CONFIG_SMP) || nr_cpu_ids == 1)
1339c51a564aSJens Wiklander 		a1 |= OPTEE_SMC_NSEC_CAP_UNIPROCESSOR;
1340c51a564aSJens Wiklander 
1341c51a564aSJens Wiklander 	invoke_fn(OPTEE_SMC_EXCHANGE_CAPABILITIES, a1, 0, 0, 0, 0, 0, 0,
1342c51a564aSJens Wiklander 		  &res.smccc);
1343c51a564aSJens Wiklander 
1344c51a564aSJens Wiklander 	if (res.result.status != OPTEE_SMC_RETURN_OK)
1345c51a564aSJens Wiklander 		return false;
1346c51a564aSJens Wiklander 
1347c51a564aSJens Wiklander 	*sec_caps = res.result.capabilities;
13486749e69cSJens Wiklander 	if (*sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF)
13496749e69cSJens Wiklander 		*max_notif_value = res.result.max_notif_value;
13506749e69cSJens Wiklander 	else
13516749e69cSJens Wiklander 		*max_notif_value = OPTEE_DEFAULT_MAX_NOTIF_VALUE;
1352ed8faf6cSJens Wiklander 	if (*sec_caps & OPTEE_SMC_SEC_CAP_RPC_ARG)
1353ed8faf6cSJens Wiklander 		*rpc_param_count = (u8)res.result.data;
1354ed8faf6cSJens Wiklander 	else
1355ed8faf6cSJens Wiklander 		*rpc_param_count = 0;
13566749e69cSJens Wiklander 
1357c51a564aSJens Wiklander 	return true;
1358c51a564aSJens Wiklander }
1359c51a564aSJens Wiklander 
1360c51a564aSJens Wiklander static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn * invoke_fn,void ** memremaped_shm)1361c51a564aSJens Wiklander optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
1362c51a564aSJens Wiklander {
1363c51a564aSJens Wiklander 	union {
1364c51a564aSJens Wiklander 		struct arm_smccc_res smccc;
1365c51a564aSJens Wiklander 		struct optee_smc_get_shm_config_result result;
1366c51a564aSJens Wiklander 	} res;
1367c51a564aSJens Wiklander 	unsigned long vaddr;
1368c51a564aSJens Wiklander 	phys_addr_t paddr;
1369c51a564aSJens Wiklander 	size_t size;
1370c51a564aSJens Wiklander 	phys_addr_t begin;
1371c51a564aSJens Wiklander 	phys_addr_t end;
1372c51a564aSJens Wiklander 	void *va;
1373c51a564aSJens Wiklander 	void *rc;
1374c51a564aSJens Wiklander 
1375c51a564aSJens Wiklander 	invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
1376c51a564aSJens Wiklander 	if (res.result.status != OPTEE_SMC_RETURN_OK) {
1377c51a564aSJens Wiklander 		pr_err("static shm service not available\n");
1378c51a564aSJens Wiklander 		return ERR_PTR(-ENOENT);
1379c51a564aSJens Wiklander 	}
1380c51a564aSJens Wiklander 
1381c51a564aSJens Wiklander 	if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
1382c51a564aSJens Wiklander 		pr_err("only normal cached shared memory supported\n");
1383c51a564aSJens Wiklander 		return ERR_PTR(-EINVAL);
1384c51a564aSJens Wiklander 	}
1385c51a564aSJens Wiklander 
1386c51a564aSJens Wiklander 	begin = roundup(res.result.start, PAGE_SIZE);
1387c51a564aSJens Wiklander 	end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
1388c51a564aSJens Wiklander 	paddr = begin;
1389c51a564aSJens Wiklander 	size = end - begin;
1390c51a564aSJens Wiklander 
1391c51a564aSJens Wiklander 	va = memremap(paddr, size, MEMREMAP_WB);
1392c51a564aSJens Wiklander 	if (!va) {
1393c51a564aSJens Wiklander 		pr_err("shared memory ioremap failed\n");
1394c51a564aSJens Wiklander 		return ERR_PTR(-EINVAL);
1395c51a564aSJens Wiklander 	}
1396c51a564aSJens Wiklander 	vaddr = (unsigned long)va;
1397c51a564aSJens Wiklander 
1398d88e0493SJens Wiklander 	rc = tee_shm_pool_alloc_res_mem(vaddr, paddr, size,
1399d88e0493SJens Wiklander 					OPTEE_MIN_STATIC_POOL_ALIGN);
1400c51a564aSJens Wiklander 	if (IS_ERR(rc))
1401d88e0493SJens Wiklander 		memunmap(va);
1402d88e0493SJens Wiklander 	else
1403c51a564aSJens Wiklander 		*memremaped_shm = va;
1404c51a564aSJens Wiklander 
1405c51a564aSJens Wiklander 	return rc;
1406c51a564aSJens Wiklander }
1407c51a564aSJens Wiklander 
1408c51a564aSJens Wiklander /* 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)1409c51a564aSJens Wiklander static void optee_smccc_smc(unsigned long a0, unsigned long a1,
1410c51a564aSJens Wiklander 			    unsigned long a2, unsigned long a3,
1411c51a564aSJens Wiklander 			    unsigned long a4, unsigned long a5,
1412c51a564aSJens Wiklander 			    unsigned long a6, unsigned long a7,
1413c51a564aSJens Wiklander 			    struct arm_smccc_res *res)
1414c51a564aSJens Wiklander {
1415c51a564aSJens Wiklander 	arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
1416c51a564aSJens Wiklander }
1417c51a564aSJens Wiklander 
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)1418c51a564aSJens Wiklander static void optee_smccc_hvc(unsigned long a0, unsigned long a1,
1419c51a564aSJens Wiklander 			    unsigned long a2, unsigned long a3,
1420c51a564aSJens Wiklander 			    unsigned long a4, unsigned long a5,
1421c51a564aSJens Wiklander 			    unsigned long a6, unsigned long a7,
1422c51a564aSJens Wiklander 			    struct arm_smccc_res *res)
1423c51a564aSJens Wiklander {
1424c51a564aSJens Wiklander 	arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
1425c51a564aSJens Wiklander }
1426c51a564aSJens Wiklander 
get_invoke_func(struct device * dev)1427c51a564aSJens Wiklander static optee_invoke_fn *get_invoke_func(struct device *dev)
1428c51a564aSJens Wiklander {
1429c51a564aSJens Wiklander 	const char *method;
1430c51a564aSJens Wiklander 
1431c51a564aSJens Wiklander 	pr_info("probing for conduit method.\n");
1432c51a564aSJens Wiklander 
1433c51a564aSJens Wiklander 	if (device_property_read_string(dev, "method", &method)) {
1434c51a564aSJens Wiklander 		pr_warn("missing \"method\" property\n");
1435c51a564aSJens Wiklander 		return ERR_PTR(-ENXIO);
1436c51a564aSJens Wiklander 	}
1437c51a564aSJens Wiklander 
1438c51a564aSJens Wiklander 	if (!strcmp("hvc", method))
1439c51a564aSJens Wiklander 		return optee_smccc_hvc;
1440c51a564aSJens Wiklander 	else if (!strcmp("smc", method))
1441c51a564aSJens Wiklander 		return optee_smccc_smc;
1442c51a564aSJens Wiklander 
1443c51a564aSJens Wiklander 	pr_warn("invalid \"method\" property: %s\n", method);
1444c51a564aSJens Wiklander 	return ERR_PTR(-EINVAL);
1445c51a564aSJens Wiklander }
1446c51a564aSJens Wiklander 
1447c51a564aSJens Wiklander /* optee_remove - Device Removal Routine
1448c51a564aSJens Wiklander  * @pdev: platform device information struct
1449c51a564aSJens Wiklander  *
1450c51a564aSJens Wiklander  * optee_remove is called by platform subsystem to alert the driver
1451c51a564aSJens Wiklander  * that it should release the device
1452c51a564aSJens Wiklander  */
optee_smc_remove(struct platform_device * pdev)1453c51a564aSJens Wiklander static int optee_smc_remove(struct platform_device *pdev)
1454c51a564aSJens Wiklander {
1455c51a564aSJens Wiklander 	struct optee *optee = platform_get_drvdata(pdev);
1456c51a564aSJens Wiklander 
1457c51a564aSJens Wiklander 	/*
1458c51a564aSJens Wiklander 	 * Ask OP-TEE to free all cached shared memory objects to decrease
1459c51a564aSJens Wiklander 	 * reference counters and also avoid wild pointers in secure world
1460c51a564aSJens Wiklander 	 * into the old shared memory range.
1461c51a564aSJens Wiklander 	 */
1462ed8faf6cSJens Wiklander 	if (!optee->rpc_param_count)
1463c51a564aSJens Wiklander 		optee_disable_shm_cache(optee);
1464c51a564aSJens Wiklander 
14656749e69cSJens Wiklander 	optee_smc_notif_uninit_irq(optee);
14666749e69cSJens Wiklander 
1467c51a564aSJens Wiklander 	optee_remove_common(optee);
1468c51a564aSJens Wiklander 
1469c51a564aSJens Wiklander 	if (optee->smc.memremaped_shm)
1470c51a564aSJens Wiklander 		memunmap(optee->smc.memremaped_shm);
1471c51a564aSJens Wiklander 
1472c51a564aSJens Wiklander 	kfree(optee);
1473c51a564aSJens Wiklander 
1474c51a564aSJens Wiklander 	return 0;
1475c51a564aSJens Wiklander }
1476c51a564aSJens Wiklander 
1477c51a564aSJens Wiklander /* optee_shutdown - Device Removal Routine
1478c51a564aSJens Wiklander  * @pdev: platform device information struct
1479c51a564aSJens Wiklander  *
1480c51a564aSJens Wiklander  * platform_shutdown is called by the platform subsystem to alert
1481c51a564aSJens Wiklander  * the driver that a shutdown, reboot, or kexec is happening and
1482c51a564aSJens Wiklander  * device must be disabled.
1483c51a564aSJens Wiklander  */
optee_shutdown(struct platform_device * pdev)1484c51a564aSJens Wiklander static void optee_shutdown(struct platform_device *pdev)
1485c51a564aSJens Wiklander {
1486ed8faf6cSJens Wiklander 	struct optee *optee = platform_get_drvdata(pdev);
1487ed8faf6cSJens Wiklander 
1488ed8faf6cSJens Wiklander 	if (!optee->rpc_param_count)
1489ed8faf6cSJens Wiklander 		optee_disable_shm_cache(optee);
1490c51a564aSJens Wiklander }
1491c51a564aSJens Wiklander 
1492f3040daaSJeffrey Kardatzke #ifdef CONFIG_OPTEE_INSECURE_LOAD_IMAGE
1493f3040daaSJeffrey Kardatzke 
1494f3040daaSJeffrey Kardatzke #define OPTEE_FW_IMAGE "optee/tee.bin"
1495f3040daaSJeffrey Kardatzke 
1496f3040daaSJeffrey Kardatzke static optee_invoke_fn *cpuhp_invoke_fn;
1497f3040daaSJeffrey Kardatzke 
optee_cpuhp_probe(unsigned int cpu)1498f3040daaSJeffrey Kardatzke static int optee_cpuhp_probe(unsigned int cpu)
1499f3040daaSJeffrey Kardatzke {
1500f3040daaSJeffrey Kardatzke 	/*
1501f3040daaSJeffrey Kardatzke 	 * Invoking a call on a CPU will cause OP-TEE to perform the required
1502f3040daaSJeffrey Kardatzke 	 * setup for that CPU. Just invoke the call to get the UID since that
1503f3040daaSJeffrey Kardatzke 	 * has no side effects.
1504f3040daaSJeffrey Kardatzke 	 */
1505f3040daaSJeffrey Kardatzke 	if (optee_msg_api_uid_is_optee_api(cpuhp_invoke_fn))
1506f3040daaSJeffrey Kardatzke 		return 0;
1507f3040daaSJeffrey Kardatzke 	else
1508f3040daaSJeffrey Kardatzke 		return -EINVAL;
1509f3040daaSJeffrey Kardatzke }
1510f3040daaSJeffrey Kardatzke 
optee_load_fw(struct platform_device * pdev,optee_invoke_fn * invoke_fn)1511f3040daaSJeffrey Kardatzke static int optee_load_fw(struct platform_device *pdev,
1512f3040daaSJeffrey Kardatzke 			 optee_invoke_fn *invoke_fn)
1513f3040daaSJeffrey Kardatzke {
1514f3040daaSJeffrey Kardatzke 	const struct firmware *fw = NULL;
1515f3040daaSJeffrey Kardatzke 	struct arm_smccc_res res;
1516f3040daaSJeffrey Kardatzke 	phys_addr_t data_pa;
1517f3040daaSJeffrey Kardatzke 	u8 *data_buf = NULL;
1518f3040daaSJeffrey Kardatzke 	u64 data_size;
1519f3040daaSJeffrey Kardatzke 	u32 data_pa_high, data_pa_low;
1520f3040daaSJeffrey Kardatzke 	u32 data_size_high, data_size_low;
1521f3040daaSJeffrey Kardatzke 	int rc;
1522f3040daaSJeffrey Kardatzke 	int hp_state;
1523f3040daaSJeffrey Kardatzke 
1524f3040daaSJeffrey Kardatzke 	if (!optee_msg_api_uid_is_optee_image_load(invoke_fn))
1525f3040daaSJeffrey Kardatzke 		return 0;
1526f3040daaSJeffrey Kardatzke 
1527f3040daaSJeffrey Kardatzke 	rc = request_firmware(&fw, OPTEE_FW_IMAGE, &pdev->dev);
1528f3040daaSJeffrey Kardatzke 	if (rc) {
1529f3040daaSJeffrey Kardatzke 		/*
1530f3040daaSJeffrey Kardatzke 		 * The firmware in the rootfs will not be accessible until we
1531f3040daaSJeffrey Kardatzke 		 * are in the SYSTEM_RUNNING state, so return EPROBE_DEFER until
1532f3040daaSJeffrey Kardatzke 		 * that point.
1533f3040daaSJeffrey Kardatzke 		 */
1534f3040daaSJeffrey Kardatzke 		if (system_state < SYSTEM_RUNNING)
1535f3040daaSJeffrey Kardatzke 			return -EPROBE_DEFER;
1536f3040daaSJeffrey Kardatzke 		goto fw_err;
1537f3040daaSJeffrey Kardatzke 	}
1538f3040daaSJeffrey Kardatzke 
1539f3040daaSJeffrey Kardatzke 	data_size = fw->size;
1540f3040daaSJeffrey Kardatzke 	/*
1541f3040daaSJeffrey Kardatzke 	 * This uses the GFP_DMA flag to ensure we are allocated memory in the
1542f3040daaSJeffrey Kardatzke 	 * 32-bit space since TF-A cannot map memory beyond the 32-bit boundary.
1543f3040daaSJeffrey Kardatzke 	 */
1544f3040daaSJeffrey Kardatzke 	data_buf = kmemdup(fw->data, fw->size, GFP_KERNEL | GFP_DMA);
1545f3040daaSJeffrey Kardatzke 	if (!data_buf) {
1546f3040daaSJeffrey Kardatzke 		rc = -ENOMEM;
1547f3040daaSJeffrey Kardatzke 		goto fw_err;
1548f3040daaSJeffrey Kardatzke 	}
1549f3040daaSJeffrey Kardatzke 	data_pa = virt_to_phys(data_buf);
1550f3040daaSJeffrey Kardatzke 	reg_pair_from_64(&data_pa_high, &data_pa_low, data_pa);
1551f3040daaSJeffrey Kardatzke 	reg_pair_from_64(&data_size_high, &data_size_low, data_size);
1552f3040daaSJeffrey Kardatzke 	goto fw_load;
1553f3040daaSJeffrey Kardatzke 
1554f3040daaSJeffrey Kardatzke fw_err:
1555f3040daaSJeffrey Kardatzke 	pr_warn("image loading failed\n");
1556f3040daaSJeffrey Kardatzke 	data_pa_high = 0;
1557f3040daaSJeffrey Kardatzke 	data_pa_low = 0;
1558f3040daaSJeffrey Kardatzke 	data_size_high = 0;
1559f3040daaSJeffrey Kardatzke 	data_size_low = 0;
1560f3040daaSJeffrey Kardatzke 
1561f3040daaSJeffrey Kardatzke fw_load:
1562f3040daaSJeffrey Kardatzke 	/*
1563f3040daaSJeffrey Kardatzke 	 * Always invoke the SMC, even if loading the image fails, to indicate
1564f3040daaSJeffrey Kardatzke 	 * to EL3 that we have passed the point where it should allow invoking
1565f3040daaSJeffrey Kardatzke 	 * this SMC.
1566f3040daaSJeffrey Kardatzke 	 */
1567f3040daaSJeffrey Kardatzke 	pr_warn("OP-TEE image loaded from kernel, this can be insecure");
1568f3040daaSJeffrey Kardatzke 	invoke_fn(OPTEE_SMC_CALL_LOAD_IMAGE, data_size_high, data_size_low,
1569f3040daaSJeffrey Kardatzke 		  data_pa_high, data_pa_low, 0, 0, 0, &res);
1570f3040daaSJeffrey Kardatzke 	if (!rc)
1571f3040daaSJeffrey Kardatzke 		rc = res.a0;
1572f3040daaSJeffrey Kardatzke 	if (fw)
1573f3040daaSJeffrey Kardatzke 		release_firmware(fw);
1574f3040daaSJeffrey Kardatzke 	kfree(data_buf);
1575f3040daaSJeffrey Kardatzke 
1576f3040daaSJeffrey Kardatzke 	if (!rc) {
1577f3040daaSJeffrey Kardatzke 		/*
1578f3040daaSJeffrey Kardatzke 		 * We need to initialize OP-TEE on all other running cores as
1579f3040daaSJeffrey Kardatzke 		 * well. Any cores that aren't running yet will get initialized
1580f3040daaSJeffrey Kardatzke 		 * when they are brought up by the power management functions in
1581f3040daaSJeffrey Kardatzke 		 * TF-A which are registered by the OP-TEE SPD. Due to that we
1582f3040daaSJeffrey Kardatzke 		 * can un-register the callback right after registering it.
1583f3040daaSJeffrey Kardatzke 		 */
1584f3040daaSJeffrey Kardatzke 		cpuhp_invoke_fn = invoke_fn;
1585f3040daaSJeffrey Kardatzke 		hp_state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "optee:probe",
1586f3040daaSJeffrey Kardatzke 					     optee_cpuhp_probe, NULL);
1587f3040daaSJeffrey Kardatzke 		if (hp_state < 0) {
1588f3040daaSJeffrey Kardatzke 			pr_warn("Failed with CPU hotplug setup for OP-TEE");
1589f3040daaSJeffrey Kardatzke 			return -EINVAL;
1590f3040daaSJeffrey Kardatzke 		}
1591f3040daaSJeffrey Kardatzke 		cpuhp_remove_state(hp_state);
1592f3040daaSJeffrey Kardatzke 		cpuhp_invoke_fn = NULL;
1593f3040daaSJeffrey Kardatzke 	}
1594f3040daaSJeffrey Kardatzke 
1595f3040daaSJeffrey Kardatzke 	return rc;
1596f3040daaSJeffrey Kardatzke }
1597f3040daaSJeffrey Kardatzke #else
optee_load_fw(struct platform_device * pdev,optee_invoke_fn * invoke_fn)1598f3040daaSJeffrey Kardatzke static inline int optee_load_fw(struct platform_device *pdev,
1599f3040daaSJeffrey Kardatzke 				optee_invoke_fn *invoke_fn)
1600f3040daaSJeffrey Kardatzke {
1601f3040daaSJeffrey Kardatzke 	return 0;
1602f3040daaSJeffrey Kardatzke }
1603f3040daaSJeffrey Kardatzke #endif
1604f3040daaSJeffrey Kardatzke 
optee_probe(struct platform_device * pdev)1605f3040daaSJeffrey Kardatzke static int optee_probe(struct platform_device *pdev)
1606c51a564aSJens Wiklander {
1607c51a564aSJens Wiklander 	optee_invoke_fn *invoke_fn;
1608c51a564aSJens Wiklander 	struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
1609c51a564aSJens Wiklander 	struct optee *optee = NULL;
1610c51a564aSJens Wiklander 	void *memremaped_shm = NULL;
1611c51a564aSJens Wiklander 	unsigned int rpc_param_count;
1612ed8faf6cSJens Wiklander 	struct tee_device *teedev;
1613c51a564aSJens Wiklander 	struct tee_context *ctx;
1614aceeafefSJens Wiklander 	u32 max_notif_value;
16156749e69cSJens Wiklander 	u32 arg_cache_flags;
16165b4018b9SJens Wiklander 	u32 sec_caps;
1617c51a564aSJens Wiklander 	int rc;
1618c51a564aSJens Wiklander 
1619c51a564aSJens Wiklander 	invoke_fn = get_invoke_func(&pdev->dev);
1620c51a564aSJens Wiklander 	if (IS_ERR(invoke_fn))
1621c51a564aSJens Wiklander 		return PTR_ERR(invoke_fn);
1622c51a564aSJens Wiklander 
1623c51a564aSJens Wiklander 	rc = optee_load_fw(pdev, invoke_fn);
1624f3040daaSJeffrey Kardatzke 	if (rc)
1625f3040daaSJeffrey Kardatzke 		return rc;
1626f3040daaSJeffrey Kardatzke 
1627f3040daaSJeffrey Kardatzke 	if (!optee_msg_api_uid_is_optee_api(invoke_fn)) {
1628c51a564aSJens Wiklander 		pr_warn("api uid mismatch\n");
1629c51a564aSJens Wiklander 		return -EINVAL;
1630c51a564aSJens Wiklander 	}
1631c51a564aSJens Wiklander 
1632c51a564aSJens Wiklander 	optee_msg_get_os_revision(invoke_fn);
1633c51a564aSJens Wiklander 
1634c51a564aSJens Wiklander 	if (!optee_msg_api_revision_is_compatible(invoke_fn)) {
1635c51a564aSJens Wiklander 		pr_warn("api revision mismatch\n");
1636c51a564aSJens Wiklander 		return -EINVAL;
1637c51a564aSJens Wiklander 	}
1638c51a564aSJens Wiklander 
1639c51a564aSJens Wiklander 	if (!optee_msg_exchange_capabilities(invoke_fn, &sec_caps,
16406749e69cSJens Wiklander 					     &max_notif_value,
1641ed8faf6cSJens Wiklander 					     &rpc_param_count)) {
1642ed8faf6cSJens Wiklander 		pr_warn("capabilities mismatch\n");
1643c51a564aSJens Wiklander 		return -EINVAL;
1644c51a564aSJens Wiklander 	}
1645c51a564aSJens Wiklander 
1646c51a564aSJens Wiklander 	/*
1647c51a564aSJens Wiklander 	 * Try to use dynamic shared memory if possible
1648c51a564aSJens Wiklander 	 */
1649c51a564aSJens Wiklander 	if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
16505b4018b9SJens Wiklander 		/*
16515b4018b9SJens Wiklander 		 * If we have OPTEE_SMC_SEC_CAP_RPC_ARG we can ask
16525b4018b9SJens Wiklander 		 * optee_get_msg_arg() to pre-register (by having
16535b4018b9SJens Wiklander 		 * OPTEE_SHM_ARG_ALLOC_PRIV cleared) the page used to pass
16545b4018b9SJens Wiklander 		 * an argument struct.
16555b4018b9SJens Wiklander 		 *
16565b4018b9SJens Wiklander 		 * With the page is pre-registered we can use a non-zero
16575b4018b9SJens Wiklander 		 * offset for argument struct, this is indicated with
16585b4018b9SJens Wiklander 		 * OPTEE_SHM_ARG_SHARED.
16595b4018b9SJens Wiklander 		 *
16605b4018b9SJens Wiklander 		 * This means that optee_smc_do_call_with_arg() will use
16615b4018b9SJens Wiklander 		 * OPTEE_SMC_CALL_WITH_REGD_ARG for pre-registered pages.
16625b4018b9SJens Wiklander 		 */
16635b4018b9SJens Wiklander 		if (sec_caps & OPTEE_SMC_SEC_CAP_RPC_ARG)
16645b4018b9SJens Wiklander 			arg_cache_flags = OPTEE_SHM_ARG_SHARED;
16655b4018b9SJens Wiklander 		else
16665b4018b9SJens Wiklander 			arg_cache_flags = OPTEE_SHM_ARG_ALLOC_PRIV;
16675b4018b9SJens Wiklander 
16685b4018b9SJens Wiklander 		pool = optee_shm_pool_alloc_pages();
1669d88e0493SJens Wiklander 	}
16705b4018b9SJens Wiklander 
1671c51a564aSJens Wiklander 	/*
1672c51a564aSJens Wiklander 	 * If dynamic shared memory is not available or failed - try static one
1673c51a564aSJens Wiklander 	 */
1674c51a564aSJens Wiklander 	if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) {
16755b4018b9SJens Wiklander 		/*
16765b4018b9SJens Wiklander 		 * The static memory pool can use non-zero page offsets so
16775b4018b9SJens Wiklander 		 * let optee_get_msg_arg() know that with OPTEE_SHM_ARG_SHARED.
16785b4018b9SJens Wiklander 		 *
16795b4018b9SJens Wiklander 		 * optee_get_msg_arg() should not pre-register the
16805b4018b9SJens Wiklander 		 * allocated page used to pass an argument struct, this is
16815b4018b9SJens Wiklander 		 * indicated with OPTEE_SHM_ARG_ALLOC_PRIV.
16825b4018b9SJens Wiklander 		 *
16835b4018b9SJens Wiklander 		 * This means that optee_smc_do_call_with_arg() will use
16845b4018b9SJens Wiklander 		 * OPTEE_SMC_CALL_WITH_ARG if rpc_param_count is 0, else
16855b4018b9SJens Wiklander 		 * OPTEE_SMC_CALL_WITH_RPC_ARG.
16865b4018b9SJens Wiklander 		 */
16875b4018b9SJens Wiklander 		arg_cache_flags = OPTEE_SHM_ARG_SHARED |
16885b4018b9SJens Wiklander 				  OPTEE_SHM_ARG_ALLOC_PRIV;
16895b4018b9SJens Wiklander 		pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
1690c51a564aSJens Wiklander 	}
16915b4018b9SJens Wiklander 
1692c51a564aSJens Wiklander 	if (IS_ERR(pool))
1693c51a564aSJens Wiklander 		return PTR_ERR(pool);
1694c51a564aSJens Wiklander 
1695c51a564aSJens Wiklander 	optee = kzalloc(sizeof(*optee), GFP_KERNEL);
1696c51a564aSJens Wiklander 	if (!optee) {
1697c51a564aSJens Wiklander 		rc = -ENOMEM;
1698c51a564aSJens Wiklander 		goto err_free_pool;
16996749e69cSJens Wiklander 	}
1700c51a564aSJens Wiklander 
1701c51a564aSJens Wiklander 	optee->ops = &optee_ops;
1702c51a564aSJens Wiklander 	optee->smc.invoke_fn = invoke_fn;
1703c51a564aSJens Wiklander 	optee->smc.sec_caps = sec_caps;
1704c51a564aSJens Wiklander 	optee->rpc_param_count = rpc_param_count;
1705ed8faf6cSJens Wiklander 
1706c51a564aSJens Wiklander 	teedev = tee_device_alloc(&optee_clnt_desc, NULL, pool, optee);
1707c51a564aSJens Wiklander 	if (IS_ERR(teedev)) {
1708c51a564aSJens Wiklander 		rc = PTR_ERR(teedev);
1709c51a564aSJens Wiklander 		goto err_free_optee;
17106749e69cSJens Wiklander 	}
1711c51a564aSJens Wiklander 	optee->teedev = teedev;
1712c51a564aSJens Wiklander 
1713c51a564aSJens Wiklander 	teedev = tee_device_alloc(&optee_supp_desc, NULL, pool, optee);
1714c51a564aSJens Wiklander 	if (IS_ERR(teedev)) {
1715c51a564aSJens Wiklander 		rc = PTR_ERR(teedev);
1716c51a564aSJens Wiklander 		goto err_unreg_teedev;
17176749e69cSJens Wiklander 	}
1718c51a564aSJens Wiklander 	optee->supp_teedev = teedev;
1719c51a564aSJens Wiklander 
1720c51a564aSJens Wiklander 	rc = tee_device_register(optee->teedev);
1721c51a564aSJens Wiklander 	if (rc)
1722c51a564aSJens Wiklander 		goto err_unreg_supp_teedev;
17236749e69cSJens Wiklander 
1724c51a564aSJens Wiklander 	rc = tee_device_register(optee->supp_teedev);
1725c51a564aSJens Wiklander 	if (rc)
1726c51a564aSJens Wiklander 		goto err_unreg_supp_teedev;
17276749e69cSJens Wiklander 
1728c51a564aSJens Wiklander 	mutex_init(&optee->call_queue.mutex);
1729c51a564aSJens Wiklander 	INIT_LIST_HEAD(&optee->call_queue.waiters);
1730c51a564aSJens Wiklander 	optee_supp_init(&optee->supp);
1731c51a564aSJens Wiklander 	optee->smc.memremaped_shm = memremaped_shm;
1732c51a564aSJens Wiklander 	optee->pool = pool;
1733c51a564aSJens Wiklander 	optee_shm_arg_cache_init(optee, arg_cache_flags);
17345b4018b9SJens Wiklander 
1735c51a564aSJens Wiklander 	platform_set_drvdata(pdev, optee);
1736787c80ccSJens Wiklander 	ctx = teedev_open(optee->teedev);
1737aceeafefSJens Wiklander 	if (IS_ERR(ctx)) {
173840eb0dcfSYang Yingliang 		rc = PTR_ERR(ctx);
173940eb0dcfSYang Yingliang 		goto err_supp_uninit;
1740aceeafefSJens Wiklander 	}
174140eb0dcfSYang Yingliang 	optee->ctx = ctx;
1742aceeafefSJens Wiklander 	rc = optee_notif_init(optee, max_notif_value);
17436749e69cSJens Wiklander 	if (rc)
17446749e69cSJens Wiklander 		goto err_close_ctx;
1745aceeafefSJens Wiklander 
17466749e69cSJens Wiklander 	if (sec_caps & OPTEE_SMC_SEC_CAP_ASYNC_NOTIF) {
17476749e69cSJens Wiklander 		unsigned int irq;
17486749e69cSJens Wiklander 
17496749e69cSJens Wiklander 		rc = platform_get_irq(pdev, 0);
17506749e69cSJens Wiklander 		if (rc < 0) {
17516749e69cSJens Wiklander 			pr_err("platform_get_irq: ret %d\n", rc);
17526749e69cSJens Wiklander 			goto err_notif_uninit;
17536749e69cSJens Wiklander 		}
17546749e69cSJens Wiklander 		irq = rc;
17556749e69cSJens Wiklander 
17566749e69cSJens Wiklander 		rc = optee_smc_notif_init_irq(optee, irq);
17576749e69cSJens Wiklander 		if (rc) {
1758787c80ccSJens Wiklander 			irq_dispose_mapping(irq);
17596749e69cSJens Wiklander 			goto err_notif_uninit;
17606749e69cSJens Wiklander 		}
17616749e69cSJens Wiklander 		enable_async_notif(optee->smc.invoke_fn);
17626749e69cSJens Wiklander 		pr_info("Asynchronous notifications enabled\n");
17636749e69cSJens Wiklander 	}
1764787c80ccSJens Wiklander 
1765787c80ccSJens Wiklander 	/*
1766c51a564aSJens Wiklander 	 * Ensure that there are no pre-existing shm objects before enabling
1767c51a564aSJens Wiklander 	 * the shm cache so that there's no chance of receiving an invalid
1768c51a564aSJens Wiklander 	 * address during shutdown. This could occur, for example, if we're
1769c51a564aSJens Wiklander 	 * kexec booting from an older kernel that did not properly cleanup the
1770c51a564aSJens Wiklander 	 * shm cache.
1771c51a564aSJens Wiklander 	 */
1772c51a564aSJens Wiklander 	optee_disable_unmapped_shm_cache(optee);
1773c51a564aSJens Wiklander 
1774c51a564aSJens Wiklander 	/*
1775ed8faf6cSJens Wiklander 	 * Only enable the shm cache in case we're not able to pass the RPC
1776ed8faf6cSJens Wiklander 	 * arg struct right after the normal arg struct.
1777ed8faf6cSJens Wiklander 	 */
1778ed8faf6cSJens Wiklander 	if (!optee->rpc_param_count)
1779ed8faf6cSJens Wiklander 		optee_enable_shm_cache(optee);
1780c51a564aSJens Wiklander 
1781c51a564aSJens Wiklander 	if (optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
1782c51a564aSJens Wiklander 		pr_info("dynamic shared memory is enabled\n");
1783c51a564aSJens Wiklander 
1784c51a564aSJens Wiklander 	rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
1785c51a564aSJens Wiklander 	if (rc)
17866749e69cSJens Wiklander 		goto err_disable_shm_cache;
17876749e69cSJens Wiklander 
1788c51a564aSJens Wiklander 	pr_info("initialized driver\n");
1789c51a564aSJens Wiklander 	return 0;
1790c51a564aSJens Wiklander 
17916749e69cSJens Wiklander err_disable_shm_cache:
17926749e69cSJens Wiklander 	if (!optee->rpc_param_count)
1793ed8faf6cSJens Wiklander 		optee_disable_shm_cache(optee);
17946749e69cSJens Wiklander 	optee_smc_notif_uninit_irq(optee);
17956749e69cSJens Wiklander 	optee_unregister_devices();
17966749e69cSJens Wiklander err_notif_uninit:
17976749e69cSJens Wiklander 	optee_notif_uninit(optee);
17986749e69cSJens Wiklander err_close_ctx:
1799aceeafefSJens Wiklander 	teedev_close_context(ctx);
1800aceeafefSJens Wiklander err_supp_uninit:
18016749e69cSJens Wiklander 	optee_shm_arg_cache_uninit(optee);
18025b4018b9SJens Wiklander 	optee_supp_uninit(&optee->supp);
18036749e69cSJens Wiklander 	mutex_destroy(&optee->call_queue.mutex);
18046749e69cSJens Wiklander err_unreg_supp_teedev:
18056749e69cSJens Wiklander 	tee_device_unregister(optee->supp_teedev);
1806c51a564aSJens Wiklander err_unreg_teedev:
18076749e69cSJens Wiklander 	tee_device_unregister(optee->teedev);
1808c51a564aSJens Wiklander err_free_optee:
18096749e69cSJens Wiklander 	kfree(optee);
1810c51a564aSJens Wiklander err_free_pool:
18116749e69cSJens Wiklander 	tee_shm_pool_free(pool);
1812c51a564aSJens Wiklander 	if (memremaped_shm)
1813c51a564aSJens Wiklander 		memunmap(memremaped_shm);
1814c51a564aSJens Wiklander 	return rc;
1815c51a564aSJens Wiklander }
1816c51a564aSJens Wiklander 
1817c51a564aSJens Wiklander static const struct of_device_id optee_dt_match[] = {
1818c51a564aSJens Wiklander 	{ .compatible = "linaro,optee-tz" },
1819c51a564aSJens Wiklander 	{},
1820c51a564aSJens Wiklander };
1821c51a564aSJens Wiklander MODULE_DEVICE_TABLE(of, optee_dt_match);
1822c51a564aSJens Wiklander 
1823c51a564aSJens Wiklander static struct platform_driver optee_driver = {
1824c51a564aSJens Wiklander 	.probe  = optee_probe,
1825c51a564aSJens Wiklander 	.remove = optee_smc_remove,
1826c51a564aSJens Wiklander 	.shutdown = optee_shutdown,
1827c51a564aSJens Wiklander 	.driver = {
1828c51a564aSJens Wiklander 		.name = "optee",
1829c51a564aSJens Wiklander 		.of_match_table = optee_dt_match,
1830c51a564aSJens Wiklander 	},
1831c51a564aSJens Wiklander };
1832c51a564aSJens Wiklander 
optee_smc_abi_register(void)1833c51a564aSJens Wiklander int optee_smc_abi_register(void)
1834c51a564aSJens Wiklander {
1835c51a564aSJens Wiklander 	return platform_driver_register(&optee_driver);
1836c51a564aSJens Wiklander }
1837c51a564aSJens Wiklander 
optee_smc_abi_unregister(void)1838c51a564aSJens Wiklander void optee_smc_abi_unregister(void)
1839c51a564aSJens Wiklander {
1840c51a564aSJens Wiklander 	platform_driver_unregister(&optee_driver);
1841c51a564aSJens Wiklander }
1842c51a564aSJens Wiklander